Construção de Consumidores Kafka
Quando usar
- Escrevendo ou depurando consumidores/produtores Kafka.
- Escolhendo estratégia de commit de offsets e garantias de entrega.
- Ajustando paralelismo de grupo de consumidores, rebalanceamento ou tratamento de mensagens mortas.
- NÃO use para processamento de streams/janelas (use
processing-streaming-data).
Fluxo de Trabalho
- [ ] Dimensione partições para o paralelismo alvo (consumidores <= partições)
- [ ] Comite offsets APÓS o processamento bem-sucedido
- [ ] Torne o sink idempotente (upsert por chave do evento)
- [ ] Lide com rebalanceamentos (comite na revogação, evite longos intervalos de poll)
- [ ] Roteie mensagens venenosas para um tópico de mensagens mortas
- Partições limitam o paralelismo. Um grupo de consumidores escala apenas até a quantidade de partições; consumidores extras ficam ociosos. Escolha partições para o pico de throughput.
- Comite após o processamento. Comite offsets assim que o trabalho for concluído de forma durável, não antes — comitar cedo perde mensagens em caso de falha.
- Sink idempotente. 'Pelo menos uma vez' significa duplicatas em retentativas; upsert por uma chave de evento estável para que o reprocessamento seja inofensivo.
- Rebalanceamentos acontecem. Comite na revogação da partição e mantenha intervalos de
poll()abaixo demax.poll.interval.mspara que o broker não remova o consumidor. - Mensagens venenosas vão para um tópico de mensagens mortas com o erro, para que um registro ruim não bloqueie a partição.
Padrões
Commit manual após o processamento:
consumer = KafkaConsumer("orders", group_id="etl",
enable_auto_commit=False,
max_poll_records=500)
for msg in consumer:
try:
upsert(process(msg)) # idempotente por chave
consumer.commit() # comite apenas após sucesso
except PoisonError:
send_to_dlq(msg)
consumer.commit() # pule o registro ruim
Produtor idempotente / transacional — defina enable.idempotence=true (remove duplicatas de
retentativas) e use transações para leitura-processamento-escrita exatamente uma vez entre tópicos.
Ajuste de throughput — aumente max.poll.records, fetch.min.bytes e
processe em lotes; mantenha o processamento rápido para evitar remoção por rebalanceamento.
Armadilhas comuns
- Auto-commit + processamento lento — offsets avançam antes da conclusão do trabalho; uma falha descarta mensagens. Prefira commit manual após o processamento.
- Mais consumidores que partições — os extras ficam ociosos; reparticione para escalar.
- Processamento longo entre polls — excede
max.poll.interval.mse dispara rebalanceamentos infinitos; processe em lotes limitados ou use um worker em segundo plano. - Sem caminho para mensagens mortas — uma mensagem venenosa bloqueia toda a partição.
- Depender de exatamente uma vez sem sink idempotente — qualquer etapa de 'pelo menos uma vez' reintroduz duplicatas.