Pular para o conteúdo principal
Sumário do livro

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 OnceProducerKafkaConsumer×mensagem pode ser perdidaAt Least OnceProducerKafkaConsumer×mensagem pode ser duplicadaExactly OnceProducerKafkaConsumer×processada exatamente uma vez
At Most Once perde mensagens sob falha antes da confirmação; At Least Once duplica mensagens sob falha após o processamento; Exactly Once, com idempotência e transações, garante processamento único mesmo sob falha.

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

GarantiaProducerConsumer
At Most Onceacks=0 ou acks=1 sem retryAuto commit, ou commit antes do processamento
At Least Onceacks=all com retry do producerCommit manual, depois que o processamento termina
Exactly OnceProducer idempotente + transaçõesConsumer 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ê?".