Modelagem de Eventos
- Eventos no passado:
PedidoCriado, nãoCriarPedido. Eventos descrevem o que aconteceu. - Schema explícito: use Avro, Protobuf ou JSON Schema. Nunca confie só no JSON livre.
- Versionamento: adicione campo
schema_version. Evolução é inevitável. - Eventos pequenos e focados: 1 evento = 1 fato. Não junte coisas só pra "economizar".
- Inclua metadados:
event_id,event_type,occurred_at,correlation_id,producer_name.
Topics
- Naming convention clara:
<dominio>.<entidade>.<evento>, ex:vendas.pedido.criado. - Não compartilhe topics entre domínios não relacionados.
- Particione com cuidado: difícil aumentar depois (quebra ordem). Comece com pelo menos 6 partições para topics importantes.
- Configure retenção:
retention.msdefine quanto tempo o Kafka guarda. Padrão é 7 dias. Avalie.
Producer
acks=allem produção. Sempre.- Habilite idempotência (
enable.idempotence=trueem libs que suportam). - Defina key: para eventos de uma mesma entidade.
- Trate erros de publicação explicitamente — não esconda exceptions.
- Use compressão:
snappyoulz4. Reduz banda e custo.
Consumer
- Comite offset depois de processar, nunca antes.
- Idempotência sempre.
- Não bloqueie indefinidamente: timeouts em chamadas externas são obrigatórios.
- Monitore o lag: diferença entre último offset publicado e último consumido. Lag crescente = problema.
- Trate envenenamento: mensagem que sempre falha não pode bloquear a fila eternamente. Use DLQ.
Observabilidade
- Métricas obrigatórias: lag por partição, mensagens/segundo, erros por consumer, tamanho da DLQ.
- Tracing distribuído: propague
traceIdnos headers da mensagem. - Logs estruturados: sempre incluam
event_id,partition,offset. - Alertas: lag alto, DLQ crescendo, consumer fora do ar.
Anti-Patterns (não faça)
- Usar Kafka como banco de dados primário (não é).
- Mensagens gigantes (>1MB). Coloque o payload em S3 e mande só a referência.
- Ignorar a DLQ. DLQ sem alerta é cemitério maldito.
- Eventos com lógica de comando ("ExecutarCobranca"). Eventos descrevem fatos, comandos pedem ações — são coisas diferentes.
- Consumer que processa rápido demais sem idempotência. Vai duplicar e ninguém vai entender por quê.
- Mudar schema sem versionar. Vai quebrar todos os consumers de uma vez.