Configurando QoS no DDS hoje: o que realmente funciona
O DDS é um padrão velho de meia, mas ainda é uma das formas mais limpas de fazer comunicação em tempo real sem depender de brokers como Kafka ou ZeroMQ. Se você tá entrando agora ou precisando ajustar algo no sistema atual, o tema de dds para hoje gira quase sempre em torno de QoS — Quality of Service. É onde a maioria das pessoas tropeça.
tema de dds para hoje:_qos em produção
QoS no DDS define como os dados trafegam entre publicadores e assinantes. Durabilidade, confiabilidade, prazo de vida, histérico. São configurações que parecem óbvias no papel mas que vão te dar trabalho se você não escolher com cuidado desde o início. Eu vi um sistema inteiro travar porque o participant não tinha um timeout definido no Reliability QoS e, em uma queda de rede, os participantes ficavam tentando se reconectar para sempre. O workaround foi criar um watchdog em nível de aplicação que reiniciava o participant após 30 segundos de idle. Levei dois dias para perceber o problema. Não leve dois dias. O que as pessoas costumam errar:
- Escolher RELIABILITY RELIABLE por padrão sem pensar no custo de rede. Cada mensagem precisa de ACK, retransmissão, estado de sessão. Em setups com dezenas de nós isso soma banda e CPU que você não tem.
- Ignorar o DEADLINE_QOS. Sem deadline configurado, o DDS não sabe que um autor já morreu. Você continua tentando enviar dados para um nó que sumiu há horas.
- Colocar DURABILITY TRANSIENT na mão achando que é só uma variação de persistente. Transient significa que os dados ficam disponíveis para quem chegar depois, mas só se o writer ainda estiver ativo. Se cair, somem.
Como configurar na prática
Vou mostrar com um exemplo em C++, que é o mais comum em sistemas embarcados e industriais. Se você usa Java ou Python, a lógica é a mesma, só muda a sintaxe da API.
Passo 1: criar o participant
O participant é a raiz de tudo. Ele controla a política de rede, discovery e default QoS. Você pode usar o padrão ou passar uma propriedade personalizada. Eu prefiro sempre passar explicitamente, mesmo que seja para manter o padrão, porque documenta a intenção.
👉 Clique no botão abaixo para saber mais sobre o assunto!
DomainParticipantQos pqos;
participant.get_default_qos(pqos);
pqos.transport.builtin.ports.host_id = 1; // id único por nó
participant.set_qos(pqos);
auto part = DomainParticipantFactory::get_instance().create_participant(0, PARTICIPANT_QOS_DEFAULT);
Passo 2: definir o topic e o publisher/subscriber
O topic é o nome do que você quer publicar. Publisher e subscriber carregam as políticas de entrega. Novamente, eu vejo muita gente usar DEFAULT e depois se perguntar por que o sistema é lento. Configure Reliability como BEST_EFFORT para telemetria de alta frequência, RELIABLE para comandos críticos.
auto topic = part->create_topic("sensor_data", "SensorType", TOPIC_QOS_DEFAULT);
auto pub = part->create_publisher(PUBLISHER_QOS_DEFAULT);
auto sub = part->create_subscriber(SUBSCRIBER_QOS_DEFAULT);
Passo 3: aplicar QoS no writer/reader
Aqui é onde a coisa fica séria. Cada writer e reader herdam QoS do publisher/subscriber, mas você pode sobrescrever individualmente.
WriterQos wqos;
pub.get_default_writer_qos(wqos);
wqos.reliability.kind = RELIABLE_RELIABILITY_QOS;
wqos.reliability.max_blocking_time = Seconds(1);
wqos.durability.kind = TRANSIENT_LOCAL_DURABILITY_QOS;
wqos.deadline.period = Seconds(1);
auto writer = pub->create_writer(topic, wqos);
ReaderQos rqos;
sub.get_default_reader_qos(rqos);
rqos.reliability.kind = BEST_EFFORT_RELIABILITY_QOS;
rqos.durability.kind = VOLATILE_DURABILITY_QOS;
rqos.deadline.period = Seconds(2);
auto reader = sub->create_reader(topic, rqos);
O problema que ninguém conta
A interoperabilidade entre implementações DDS. Vocês podem usar CycloneDDS, OpenDDS, Connext, RTI. Cada um tem diferenças sutis em como respeita os QoS. Eu precisei migrar de OpenDDS para CycloneDDS em um projeto de satélite porque o deadlock na implementação de discover dos tipos genéricos era impossível de resolver. A migração levou uma semana. O código em si mudou em duas linhas. Outro problema: versionamento de tipos. DDS usa IDL como contrato. Se você mudar o tipo e não atualizar o-DDS-protocolo, os dados são descartados silenciosamente. Não dá erro. Só some. Solução: manter um esquema centralizado e rodar validação IDL em CI antes de cada deploy.
Alternativas quando DDS não serve
Se o seu sistema não precisa de semântica de publish-subscribe com QoS rico, DDS é overkill. Para pipelines de dados simples, ZeroMQ ou até gRPC com streaming resolvem em tempo menor. DDS brilha quando você precisa de tolerância a falhas, descoberta automática e garantias de entrega com prazos. Fora disso, você está pagando complexo por algo que não precisa. Se quiser testar localmente antes de subir em produção, o CycloneDDS vem com um demo server que roda em containers Docker. É rápido de levantar e evita o trabalho de config manual de rede.