Parte IV — Confiabilidade
Garantias de entrega
At Most Once, At Least Once e Exactly Once — o que cada garantia realmente promete, e onde exactly-once para de valer.
Nesta página
Os Capítulos 7 e 9 já tocaram em perda e duplicidade de mensagens, cada um do seu ângulo (commit, retry). Este capítulo nomeia formalmente os três contratos que resumem esse comportamento — e desfaz um mal-entendido comum sobre o que "exactly-once" realmente cobre.
As três garantias
At Most Once
A mensagem é entregue no máximo uma vez — nunca duplicada, mas pode ser perdida. Acontece quando o commit (ou o ack do producer) ocorre antes de qualquer confirmação de sucesso do passo seguinte.
At Least Once
A mensagem é entregue pelo menos uma vez — nunca perdida, mas pode ser duplicada. Acontece quando o commit (ou retry do producer) só ocorre depois que o passo anterior foi confirmado, aceitando reprocessamento em caso de falha entre a confirmação e o registro dela.
Exactly Once
A mensagem é processada exatamente uma vez do ponto de vista do efeito observável — nem perdida, nem duplicada — através de uma combinação de producer idempotente, transações e consumer idempotente, não de uma garantia mágica de entrega única.
Onde a garantia é decidida
Do lado do producer, a configuração acks decide o trade-off entre disponibilidade e durabilidade
(Capítulo 5): acks=0 favorece velocidade e aceita perda; acks=all favorece durabilidade. Do lado do
consumer, a ordem entre processamento e commit (Capítulo 7) decide entre perda (commit antes de processar) e
duplicidade (commit depois de processar, mas com risco de falha no meio).
Configuração típica por garantia
| Garantia | Producer | Consumer |
|---|---|---|
| At Most Once | acks=0 ou acks=1 sem retry | Auto commit, ou commit antes do processamento |
| At Least Once | acks=all com retry do producer | Commit manual, depois que o processamento termina |
| Exactly Once | Producer idempotente + transações | Consumer idempotente, ou transação que abrange leitura+escrita |
Por que At Least Once é o padrão prático
At Most Once raramente é aceitável em sistemas financeiros
Perder uma mensagem silenciosamente — um evento de pagamento que nunca é processado — é geralmente pior do que processá-lo duas vezes, porque a duplicidade pelo menos é detectável e corrigível com idempotência, enquanto a perda sequer deixa rastro. Por isso, a configuração mais comum em sistemas financeiros é At Least Once, combinada com processamento idempotente no consumer.
Isso explica por que a idempotência (Capítulo 11) não é um "extra de qualidade" — ela é o complemento necessário do At Least Once, que é a garantia mais usada na prática.
Exactly Once: o que ela cobre e o que não cobre
"Exactly Once significa que a mensagem nunca é processada duas vezes, ponto final"
Exactly-once semantics (EOS) do Kafka garante processamento exatamente uma vez dentro do ecossistema Kafka — entre um tópico de entrada, o processamento, e a escrita em outro tópico Kafka, usando transações. No momento em que o efeito sai do Kafka — uma chamada HTTP, uma escrita em banco de dados externo, um e-mail enviado — essa garantia deixa de valer automaticamente, porque esses sistemas externos não participam da transação do Kafka.
Exactly-once não elimina a necessidade de idempotência no mundo real
Se o consumer escreve em um banco de dados ou chama uma API externa como parte do processamento, essa escrita fica fora do escopo da transação do Kafka. Uma falha exatamente depois de processar mas antes de Kafka confirmar o commit da transação ainda pode levar a uma repetição desse efeito externo. Por isso, sistemas que integram Kafka com bancos de dados e APIs externas continuam precisando de idempotência nessas integrações, mesmo usando exactly-once semantics internamente.
Como aparece em entrevistas
"O que é exactly-once e ele resolve duplicidade de vez?" é a armadilha mais comum desta seção. A resposta fraca diz "sim, elimina duplicidade". A resposta forte explica o escopo: EOS cobre o fluxo Kafka-para-Kafka via transações, mas qualquer efeito colateral fora do Kafka (banco, API, e-mail) continua exigindo idempotência própria.
Dica de entrevista
Ao ser perguntado sobre exactly-once, sempre delimite o escopo: "dentro do Kafka, entre ler de um tópico e escrever em outro, via transações". Isso sinaliza que você entende a fronteira da garantia, não só o nome.
Relação com Java e Spring Boot
Em Spring Kafka, acks=all e enable.idempotence=true no producer (o padrão desde versões recentes do
client) evitam duplicação de mensagens causada por retries automáticos do próprio producer. Para
exactly-once semantics completo entre tópicos, usa-se KafkaTransactionManager envolvendo leitura e escrita
em uma mesma transação Kafka. Mas assim que o listener chama um serviço HTTP externo ou grava em um banco
relacional fora dessa transação, a responsabilidade de evitar duplicidade volta a ser do desenvolvedor —
tipicamente via constraint de unicidade e checagem de idempotência (Capítulo 11).
Notificação de PIX recebido
O notificacao-service roda com At Least Once: se ele cair depois de enviar a notificação push mas antes de
comitar o offset, o evento será reprocessado e uma segunda notificação pode ser enviada. Isso é aceitável
para uma notificação (o pior caso é o cliente receber dois avisos), mas seria inaceitável para o
saldo-service, que precisa de proteção explícita contra crédito duplicado — daí a diferença de rigor de
idempotência entre os dois consumers do mesmo evento.
Resumo
At Most Once nunca duplica, mas pode perder. At Least Once nunca perde, mas pode duplicar — e é o padrão prático em sistemas financeiros, combinado com idempotência. Exactly Once, via transações do Kafka, garante processamento único apenas dentro do ecossistema Kafka; qualquer efeito colateral externo (banco, API, e-mail) continua exigindo idempotência própria, independentemente da garantia configurada internamente.
Pode vir a seguir
Prováveis follow-ups: "como você evitaria processamento duplicado?" (Capítulo 11) e "qual configuração de
acks você usaria para um tópico de transações financeiras, e por quê?".