Pular para o conteúdo principal

Conceitoavançado

Mensageria

Visão Geral

Mensageria é comunicação por mensagens intermediadas por um componente durável, em vez de chamadas diretas.

Ela desacopla produtor e consumidor no tempo. E introduz um conjunto de garantias — e de ausências de garantia — que precisam ser conhecidas antes de adotar, não descobertas em produção.

Problema

Chamada direta acopla no tempo: se o destino está fora, a origem está fora.

Mensageria resolve isso, e a escolha de qual modelo costuma ser feita pela ferramenta disponível em vez de pelo padrão de consumo — o que produz sistemas onde o modelo não corresponde ao uso.

Os dois modelos têm semânticas distintas, e confundi-los gera expectativas que o canal não cumpre.

Conceitos Centrais

Fila versus log de eventos

FilaLog de eventos
Mensagem consumidaSomePermanece
ConsumidoresCompetem pela mensagemCada um lê tudo
Reprocessar históricoImpossívelReposicionar e reler
OrdemFrágil com vários consumidoresGarantida por partição
Posição de leituraDo brokerDo consumidor
Uso típicoDistribuir trabalhoDistribuir fatos

Fila modela trabalho: uma tarefa, um executor. Vários consumidores competem, e escalar é adicionar consumidores.

Log modela fatos: o evento aconteceu e vários interessados reagem, cada um no seu ritmo, cada um com sua posição.

A escolha errada aparece assim: usar fila quando vários sistemas precisam do mesmo evento — e acabar criando uma fila por consumidor, com o produtor publicando N vezes. Ou usar log para distribuir trabalho — e ter que coordenar quem processa o quê.

O canal é uma rede

Independentemente do modelo, o canal herda os problemas de falha de rede, e isso produz três garantias que a aplicação precisa tratar:

Entrega ao menos uma vez — duplicação vai acontecer.

Ordem apenas por partição — não há ordem global.

Mensagens que sempre falham — precisam de dead-letter queue.

Nenhuma dessas é opcional. Adotar mensageria sem tratá-las é adotar o risco sem o mecanismo.

Confirmação e visibilidade

O consumidor confirma após processar com sucesso. Confirmar antes perde a mensagem se o processamento falhar.

Entre a entrega e a confirmação, a mensagem fica invisível para outros consumidores por um tempo. Se esse tempo for menor que o processamento, a mensagem é reentregue enquanto ainda está sendo processada — duplicação sistemática.

Esse valor precisa ser calibrado a partir do percentil alto do tempo de processamento, não estimado.

O produtor também tem um problema

Publicar uma mensagem e gravar no banco não são atômicos. Pode gravar e não publicar, ou publicar e falhar ao gravar.

A solução é o padrão outbox: a mensagem é gravada numa tabela na mesma transação do dado, e um processo separado a publica. Ver evento de domínio.

Ignorar isso produz perda silenciosa de mensagem — o modo de falha mais difícil de diagnosticar, porque não há erro em lugar nenhum.

Push e pull

Push — o broker envia ao consumidor. Latência baixa, e o consumidor pode ser sobrecarregado se não houver controle de fluxo. Ver backpressure.

Pull — o consumidor busca quando pode. Controle natural de ritmo, ao custo de latência de intervalo.

A maioria dos sistemas modernos usa pull com espera longa: o consumidor pede, e a conexão fica aberta até haver mensagem ou expirar. Combina o controle do pull com a latência do push.

Modelo Mental

Fila distribui trabalho. Log distribui fatos. A pergunta é se a mensagem é uma tarefa para alguém ou um acontecimento para quem interessar.

Quando Usar

  • O produtor não precisa da resposta.
  • O consumidor pode processar com atraso.
  • É preciso absorver pico.
  • Vários interessados no mesmo fato — aí, log.
  • O trabalho é demorado e não cabe numa requisição.

Quando Não Usar

Quando a resposta é necessária. Ver request/response.

Sem idempotência no consumidor. A duplicação vai acontecer.

Sem dead-letter. Uma mensagem ruim trava o consumo.

Sem outbox, quando a mensagem representa um fato persistido. Perda silenciosa.

Como banco de dados. Um log com retenção infinita usado para consulta não tem as garantias nem os índices de um banco.

Quando a consistência forte é requisito. Mensageria implica consistência eventual.

Alternativas

  • Chamada síncrona — quando a resposta importa.
  • Tabela como fila — para volume baixo, usar o banco existente evita mais um componente a operar.
  • Chamada direta com retentativa — quando há um consumidor e ele é confiável.
  • Processamento agendado — quando a latência tolerada é alta.

Trade-offs

Com mensageriaChamada direta
Produtor independe do consumidorAcoplado no tempo
Pico absorvidoPropagado
Novo consumidor sem tocar o produtorToca
Duplicação, ordem, dead-letter a tratarSemântica simples
Fluxo fragmentadoRastreável
Mais um componente a operarNenhum

Modos de Falha

Consumidor não idempotente. Efeito duplicado.

Perda por ausência de outbox. Transação confirmada, mensagem não publicada.

Visibilidade menor que o processamento. Duplicação sistemática.

Acúmulo silencioso. A fila cresce e ninguém percebe.

Consumidor mais lento que o produtor. A fila só adia o colapso.

Retenção mal configurada. Num log, mensagens expiram antes de um consumidor lento alcançá-las.

Erros Comuns

Escolher o modelo pela ferramenta disponível. Fila e log de eventos resolvem problemas diferentes — trabalho a executar uma vez versus fato que muitos leem no próprio ritmo. Usar o que já está instalado para os dois força um dos dois casos a um formato errado.

Não calibrar o tempo de visibilidade. Se ele é menor que o tempo de processamento, a mensagem reaparece para outro consumidor enquanto o primeiro ainda trabalha — e o efeito acontece duas vezes.

Não monitorar profundidade e idade da mensagem mais antiga. As duas medem coisas distintas: profundidade acusa pico de entrada, idade acusa consumidor parado. Uma fila com dez mensagens paradas há duas horas é mais grave que uma com dez mil em escoamento.

Publicar dentro da transação sem outbox. O banco e o broker não compartilham transação: um pode confirmar e o outro falhar, e o resultado é evento sem fato ou fato sem evento.

Usar o log como armazenamento de consulta. Ele é otimizado para leitura sequencial por posição. Perguntar "qual o estado atual do pedido X" exige varrer, e a resposta piora à medida que o histórico cresce.

Exemplo Real

Um sistema de logística usava fila para notificar quatro áreas sobre entregas concluídas: faturamento, atendimento, análise e o cliente.

Como fila entrega a um consumidor, a solução foi o produtor publicar em quatro filas separadas.

Três problemas apareceram.

Acoplamento no produtor. Adicionar um quinto interessado exigia alterar o serviço de entregas e implantá-lo. Em dois anos, isso aconteceu três vezes.

Publicação parcial. Publicar em quatro filas não é atômico. Numa indisponibilidade momentânea do broker, mensagens foram para duas filas e não para as outras duas — e faturamento processou entregas que atendimento nunca soube que existiam.

Reprocessamento impossível. Quando análise precisou recalcular métricas de seis meses, não havia como: as mensagens tinham sido consumidas e não existiam mais.

A migração para log de eventos resolveu os três.

O produtor publica uma vez, num tópico. Cada consumidor lê tudo, com sua própria posição. O quinto interessado foi adicionado sem tocar o produtor.

A publicação única com outbox eliminou a parcialidade.

E o reprocessamento virou reposicionar a leitura — a análise recalculou seis meses em duas horas, lendo o histórico retido.

O que a equipe aprendeu: a fila não estava errada como tecnologia. Estava errada como modelo — o caso era distribuição de fatos, não de trabalho, e o sintoma de ter escolhido errado foi ter que publicar N vezes.

Conceitos Relacionados

Exercício Prático

Para cada uso de mensageria no seu sistema, responda: a mensagem é trabalho para alguém ou fato para quem interessar?

Se for fato e você usa fila, verifique quantas filas o produtor precisa alimentar. Mais de uma é o sintoma.

Perguntas de Entrevista

  • Qual a diferença semântica entre fila e log de eventos?
  • Por que o padrão outbox é necessário?
  • O que acontece se o tempo de visibilidade for menor que o de processamento?

Para Aprofundar

  • Hohpe, Gregor; Woolf, Bobby. Enterprise Integration Patterns, 2003.
  • Kleppmann, Martin. Designing Data-Intensive Applications. O'Reilly, 2017 — capítulo 11.
Terminou de ler este documento?Seu progresso fica salvo apenas neste navegador.