Pular para o conteúdo principal

Conceitointermediário

Mensagens Duplicadas

Visão Geral

Num sistema com entrega ao menos uma vez, a mesma mensagem chegará duas vezes. Não é hipótese — é certeza estatística ao longo do tempo.

O que a arquitetura decide não é se a duplicação acontece. É se ela produz efeito.

Problema

A duplicação tem várias origens, e nenhuma delas é evitável:

Retentativa do produtor. A confirmação se perdeu; ele reenvia.

Reentrega do broker. O consumidor não confirmou a tempo — porque estava lento, não porque falhou.

Rebalanceamento. Consumidores trocam de partição e reprocessam mensagens em andamento.

Reprocessamento deliberado. Alguém reposiciona a leitura para corrigir um defeito, e mensagens já processadas voltam.

A última é frequentemente esquecida no projeto e é a mais comum na operação: toda correção de defeito num consumidor implica reprocessar.

Conceitos Centrais

Duas estratégias

Idempotência da operação. O efeito é o mesmo executando uma ou N vezes. Ver idempotência. É a solução mais robusta, porque não depende de detectar a duplicata.

Deduplicação explícita. Registrar identificadores já processados e descartar repetições.

A primeira é preferível quando possível — ela funciona mesmo com identificador perdido ou janela expirada. A segunda é necessária quando o efeito não pode ser tornado idempotente.

Na prática, sistemas maduros usam as duas: idempotência onde dá, deduplicação como rede.

Identificador de mensagem versus identificador de negócio

Detalhe que decide a correção da deduplicação.

O identificador da mensagem, gerado pelo broker, muda quando o produtor reenvia — porque é uma mensagem nova, com o mesmo conteúdo. Deduplicar por ele não detecta duplicação de produtor.

O identificador de negócio — o pedido, a transação, a operação — identifica a intenção e é estável entre reenvios.

Deduplique pelo identificador de negócio. É o mesmo princípio da chave de idempotência: a chave identifica a intenção, não a tentativa.

Persistida ou por janela

Chave persistidaJanela em cache
GarantiaCompletaDentro da janela
CustoEscrita por mensagemMemória
Volume altoCaroViável
Reprocessamento antigoDetectadoNão detectado

A janela é adequada para volume alto onde a duplicação realista acontece em segundos ou minutos. A chave persistida é necessária quando o reprocessamento pode ser de dias atrás.

O erro comum é usar janela e esquecer que reprocessamento deliberado ultrapassa qualquer janela razoável.

A verificação e o efeito precisam ser atômicos

Se o consumidor verifica a chave, processa, e depois registra — existe uma janela em que dois consumidores verificam ao mesmo tempo e ambos processam.

A forma correta é a inserção da chave fazer parte da mesma transação do efeito, com restrição de unicidade fazendo o trabalho:

BEGIN
INSERT INTO processados (chave) VALUES (:chave) -- falha se já existe
... aplica o efeito ...
COMMIT

A violação de unicidade indica duplicata, e a transação inteira é descartada. Sem janela de corrida.

Deduplicação não resolve tudo

Se o efeito sai do sistema — uma chamada a serviço externo — a deduplicação local não impede que a chamada aconteça duas vezes se o processo morrer entre a chamada e a confirmação.

Ali a idempotência precisa estar do outro lado, com chave enviada na chamada.

O tamanho da janela vem do comportamento real

Escolher a janela de deduplicação por intuição — "uma hora parece razoável" — é como o mecanismo falha em produção.

A janela precisa cobrir o maior intervalo possível entre duas entregas da mesma mensagem, que é a soma de três coisas mensuráveis:

janela ≥ atraso máximo de reentrega do intermediário
+ atraso máximo do consumidor
+ margem para reprocessamento operacional

O terceiro termo é o que mais surpreende. Se a operação inclui reprocessar um período depois de um incidente, a janela precisa cobrir esse período inteiro — e aí ela deixa de ser uma janela e passa a ser deduplicação persistente.

A regra prática: se o sistema tem qualquer procedimento de reprocessamento, a janela não serve.

Modelo Mental

A mensagem vai chegar duas vezes. A pergunta é se o mundo nota.

Quando Usar

  • Todo consumidor de mensagem, sem exceção.
  • Toda operação com efeito colateral externo.
  • Especialmente onde o efeito é irreversível — cobrança, envio, emissão de documento.

Quando Não Usar

Quando a operação é naturalmente idempotente. Definir um valor absoluto, marcar um estado. Vale verificar se continua sendo — idempotência natural quebra com o tempo.

Quando o efeito duplicado é inofensivo e barato. Um log duplicado. Vale reconhecer explicitamente, não presumir.

Deduplicação por janela quando o reprocessamento é comum. A janela não cobre.

Deduplicação pelo identificador da mensagem. Não detecta reenvio do produtor.

Alternativas

  • Idempotência da operação — a preferível.
  • Restrição de unicidade no banco — o próprio armazenamento rejeita a duplicata, sem código de deduplicação.
  • Operações comutativas e absolutas — reformular de "some" para "defina".
  • Reconciliação — aceitar e corrigir depois, quando a detecção em tempo real é cara.

Trade-offs

DeduplicarNão deduplicar
Efeito único garantidoDuplicação possível
Escrita adicional por mensagemNenhuma
Armazenamento de chaves a manterNada
Latência ligeiramente maiorMenor
PersistidaJanela
Garantia completaDentro da janela
Custo por mensagemCusto de memória
Detecta reprocessamento antigoNão

Modos de Falha

Deduplicação não atômica. Dois consumidores processam simultaneamente.

Chave errada. Identificador da mensagem em vez do de negócio.

Janela curta. Reprocessamento ultrapassa.

Chaves sem expiração. Vazamento no armazenamento.

Efeito externo não protegido. A deduplicação local não cobre a chamada que já saiu.

Erros Comuns

Assumir que o broker resolve. A duplicata que importa nasce da retentativa do produtor e do reenvio após falha do consumidor — os dois pontos fora do alcance do broker.

Deduplicar pelo identificador da mensagem. O produtor que reenvia gera um identificador novo para a mesma intenção de negócio. A chave precisa vir do domínio — o identificador do pedido, não o do envelope.

Verificar e processar em transações separadas. Entre a consulta "já processei?" e a gravação existe uma janela em que a segunda cópia também consulta e também recebe não. Duas cópias concorrentes passam pela verificação.

Não considerar reprocessamento deliberado ao dimensionar a janela. Uma janela de deduplicação de 24 horas bloqueia o reprocesso de sete dias que a correção de um defeito exige — ou o libera para duplicar tudo.

Não expirar as chaves. O armazenamento de deduplicação cresce sem limite e vira, ele próprio, o gargalo do consumidor que deveria proteger.

Exemplo Real

Um consumidor de eventos de venda gravava comissões de vendedores.

A deduplicação usava o identificador da mensagem, guardado em cache com janela de uma hora.

Dois incidentes.

O primeiro foi um defeito no cálculo de comissão para um tipo de produto. Corrigido o código, a equipe reposicionou a leitura para reprocessar as vendas do mês. As mensagens tinham identificadores novos — eram entregas novas — e a janela de uma hora era irrelevante para eventos de semanas atrás.

Todas as comissões do mês foram lançadas de novo. Os vendedores receberam o dobro, e o estorno gerou conversa com o jurídico trabalhista.

O segundo foi mais sutil. Sob carga, dois consumidores processaram a mesma mensagem: um verificou o cache, e antes de gravar a chave, o outro verificou também. Ambos passaram.

A reformulação trocou as duas decisões.

Chave de negócio — o identificador da venda — em vez do identificador da mensagem. Reprocessar a mesma venda passa a ser detectado independentemente de quantas vezes a mensagem seja reentregue ou reenviada.

Persistência com unicidade, na mesma transação do lançamento da comissão. A inserção da chave e o lançamento acontecem juntos ou nenhum acontece. A corrida deixou de ser possível.

E as chaves ganharam expiração de 90 dias — prazo maior que qualquer reprocessamento plausível, e curto o bastante para não acumular indefinidamente.

O reprocessamento seguinte, seis meses depois, correu sem incidente: as vendas já comissionadas foram descartadas silenciosamente, e apenas as novas foram lançadas.

Conceitos Relacionados

Exercício Prático

Para cada consumidor do seu sistema, responda: como ele detecta duplicata? Pela chave de negócio ou da mensagem? A verificação e o efeito são atômicos?

Depois faça a pergunta operacional: se você precisasse reprocessar o último mês, o que aconteceria?

Perguntas de Entrevista

  • Por que deduplicar pelo identificador da mensagem é insuficiente?
  • Por que a verificação e o efeito precisam ser atômicos?
  • Quando janela em cache é suficiente e quando não é?

Para Aprofundar

  • Helland, Pat. Idempotence Is Not a Medical Condition. ACM Queue, 2012.
  • Kleppmann, Martin. Designing Data-Intensive Applications. O'Reilly, 2017.
Terminou de ler este documento?Seu progresso fica salvo apenas neste navegador.