M03·05Problemas Reais (e Como Sofrer Menos)

CAPÍTULO 05

Problemas Reais (e Como Sofrer Menos)

Perda de mensagens, duplicidade, ordem dos eventos — os três problemas que derrubam sistemas em produção e como evitá-los.

Por Thiago Souza7 min de leituraAtualizado em 2026-05

Perda de Mensagens

Cenários onde uma mensagem some:

  1. Producer envia mas não confirmou recebimento e crashou. → mensagem nunca foi pro Kafka.
  2. Kafka recebe mas não replicou e o broker líder caiu. → perdida.
  3. Consumer "comitou" o offset antes de processar e crashou. → próximo consumer pula essa mensagem.

Garantias de Entrega

Existem 3 níveis:

GarantiaComportamentoQuando usar
At-most-oncePode perder, nunca duplicaMétricas onde perder um ponto não doi
At-least-onceNunca perde, pode duplicarPadrão, com consumers idempotentes
Exactly-onceNunca perde, nunca duplica (caro)Transações financeiras críticas

Como configurar at-least-once no producer?

acks=all              → espera todas as réplicas confirmarem
retries=Integer.MAX   → tenta indefinidamente
enable.idempotence=true → evita duplicação por retry do producer

No consumer, processe antes de comitar offset:

go
for {
    msg := readMessage()
    err := processMessage(msg)   // 1. processa
    if err == nil {
        commitOffset(msg)         // 2. só depois comita
    }
}

Duplicidade

Se você usa at-least-once (e provavelmente é o seu caso), mensagens vão duplicar em algum momento. Cenários:

  1. Consumer processou mas crashou antes de comitar offset → outro consumer reprocessa.
  2. Producer fez retry de uma mensagem que já tinha sido enviada.
  3. Rebalanceamento de partições durante deploy.

Solução: idempotência (veja o capítulo anterior). É inevitável, prepare-se.

Ordem dos Eventos

A ordem só é garantida dentro de uma partição. Se você publica eventos sem key, eles se espalham entre partições e a ordem se perde.

Cenário problemático:

Eventos do pedido 123:
  T=1: PedidoCriado     → vai pra partição 0
  T=2: PagamentoAprovado → vai pra partição 2
  T=3: PedidoEnviado    → vai pra partição 1

O consumer que lê a partição 1 pode receber PedidoEnviado antes do PedidoCriado aparecer. Caos.

Solução: use uma chave consistente. Exemplo: pedidoId como key. Assim, todos os eventos de um mesmo pedido vão pra mesma partição e mantêm a ordem.

Eventos do pedido 123 (todos com key="123"):
  T=1: PedidoCriado     → partição 0
  T=2: PagamentoAprovado → partição 0
  T=3: PedidoEnviado    → partição 0
  (ordem garantida)
Identifique o que é a "entidade" cuja ordem importa, e use o ID dela como key.