Knowledge

Arquitetura Event-Driven com Kafka: Além de Filas de Mensagens

Como Apache Kafka habilita verdadeiras arquiteturas event-driven com streams de eventos persistentes, grupos de consumidores e semânticas exactly-once.

12/03/20267 min de leituraKnowledge
Arquitetura Event-Driven com Kafka: Além de Filas de Mensagens

Resumo executivo

Como Apache Kafka habilita verdadeiras arquiteturas event-driven com streams de eventos persistentes, grupos de consumidores e semânticas exactly-once.

Ultima atualizacao: 12/03/2026

Resumo executivo

Filas de mensagens tradicionais (RabbitMQ, SQS) são projetadas para distribuição de tarefas: aqui está um job, por favor processe-o. Apache Kafka é projetado para algo fundamentalmente diferente: event streaming.

A distinção é profunda. Uma fila mantém mensagens até serem consumidas, depois elas somem. Kafka retém eventos por um período de retenção configurável, permitindo que múltiplos consumidores replaiem o stream de eventos em seu próprio ritmo. Esse desacoplamento habilita novos casos de uso que são impossíveis com filas tradicionais:

  • Consumidores tardios: Novos serviços podem consumir eventos históricos para reconstruir estado.
  • Replay de eventos: Bugs podem ser corrigidos e consumidores podem "rebobinar" para reprocessar eventos.
  • Sistemas downstream múltiplos: Analytics, indexação de busca e lógica de negócio podem todos consumir o mesmo stream de eventos independentemente.

Em 2026, Kafka se tornou a escolha default para arquiteturas event-driven que requerem streams de eventos duráveis e replayáveis.

Conceitos fundamentais: Por que Kafka é diferente

Topics, partitions e consumer groups

Kafka organiza eventos em topics, que são divididos em partitions. Cada partition é um log ordenado e imutável de eventos:

Topic: orders
Partition 0: [event1] → [event2] → [event3] → [event4]
Partition 1: [event5] → [event6] → [event7] → [event8]

Eventos dentro de uma partition mantêm ordenação estrita. Através de partitions, ordenação não é garantida.

Consumer groups fornecem o mecanismo de scaling. Cada partition é consumida por exatamente um consumidor dentro de um grupo. Se você tem 4 partitions e 4 consumidores em um grupo, cada consumidor lida com uma partition. Se você adiciona um 5º consumidor, ele fica idle até partitions serem rebalanced.

Esse design habilita tanto processamento paralelo (múltiplas partitions) quanto consumidores stateful (cada consumidor sabe exatamente quais eventos processou).

Retention vs TTL

Filas de mensagens tipicamente deletam mensagens após consumo. Kafka retém eventos baseado em tempo ou tamanho:

bash# Retain events por 7 dias
log.retention.hours=168

# Ou retém eventos até 10GB
log.retention.bytes=10737418240

Essa janela de retention é o que habilita replayability. Se um consumidor crasha e precisa reprocessar a última hora de eventos, Kafka pode fornecer.

Quando Kafka acelera entrega

Kafka oferece ganhos de velocidade mensuráveis em cenários específicos:

  • Propagação de estado: Quando serviços precisam ficar sincronizados através de eventos em vez de polling de databases.
  • Patterns multi-consumidor: Quando múltiplos sistemas downstream precisam dos mesmos eventos independentemente.
  • Event sourcing: Quando o log de eventos em si é a fonte de verdade para estado de aplicação.
  • Pipelines de analytics: Quando business intelligence e monitoramento em tempo real precisam de acesso ao mesmo stream de eventos.

Perguntas de decisão para seu contexto:

  • Você precisa replayar eventos para novos consumidores ou cenários de recuperação?
  • Você tem múltiplos sistemas independentes que precisam dos mesmos eventos?
  • Ordenação de eventos dentro de uma entidade de negócio é importante (ex: todos os eventos para um único usuário)?

Patterns de consumidor e anti-patterns

Pattern 1: Delivery at-least-once

Kafka garante delivery at-least-once. Se um consumidor crasha após processar um evento mas antes de commit seu offset, ele reprocessará esse evento no restart.

go// Consumidor com semântica at-least-once
for {
    records := consumer.Poll(100 * time.Millisecond)
    
    for _, record := range records {
        // Processa evento
        processEvent(record)
        
        // Commit offset APÓS processamento bem-sucedido
        consumer.Commit(record)
    }
}

Implicação operacional: Consumidores devem ser idempotentes. Reprocessar o mesmo evento duas vezes deve ter o mesmo resultado que processá-lo uma vez.

Pattern 2: Consumer groups para scaling horizontal

Consumer groups habilitam scaling horizontal sem coordenação:

bash# Três instâncias do mesmo serviço
orders-consumer-1: partitions [0, 1]
orders-consumer-2: partitions [2, 3]
orders-consumer-3: partitions [4, 5]

Quando uma nova instância junta ou sai, Kafka automaticamente rebalanceia partitions através do grupo.

Anti-pattern: Consumidores síncronos em pipelines de eventos

Um erro comum é tornar consumidores síncronos, encadeando-os:

Producer → [Kafka] → Consumer A → Consumer B → Consumer C

Isso derrota o propósito de Kafka. Cada consumidor deve processar independentemente:

Producer → [Kafka] → Consumer A
                → Consumer B
                → Consumer C

Estratégias de evolução de schema

À medida que seus schemas de evento evoluem, você precisa de estratégias para manter compatibilidade:

Mudanças backward-compatible

  • Adicionar campos opcionais
  • Renomear campos com aliases
  • Adicionar valores default

Mudanças forward-compatible

  • Remover campos opcionais
  • Mudar tipos de campo com converters

Integração com Schema Registry

Confluent Schema Registry fornece gerenciamento de schema e enforcement de compatibilidade:

java// Producer com validação de schema
Producer<String, OrderEvent> producer = new KafkaProducer<>(
    props,
    new StringSerializer(),
    new KafkaAvroSerializer(schemaRegistry)
);

O registry garante que produtores enviem apenas schemas válidos e consumidores possam deserialize corretamente.

Considerações operacionais

Kafka introduz complexidade operacional que deve ser gerenciada:

Gerenciamento de broker

  • Falhas de broker: Kafka é projetado para tolerar falhas de broker com replication. Configure replication factors apropriadas para seus requisitos de durabilidade (tipicamente 3 para produção).
  • Rebalancing: Quando consumer groups mudam, partitions são rebalanced. Configure timeouts de rebalancing apropriados para prevenir consumidores travados.
  • Alocação de recursos: Kafka é intensive em memory e I/O. Aloque recursos dedicados para evitar contention com outros serviços.

Monitoramento de lag de consumidor

Consumer lag—a diferença entre o último evento em Kafka e o último evento processado por um consumidor—é a métrica crítica de saúde:

bash# Monitore lag usando CLI do Kafka
kafka-consumer-groups --bootstrap-server localhost:9092 \
    --group orders-consumer --describe

Alertar sobre lag crescente habilita intervenção proativa antes que consumidores caiam permanentemente atrás.

Dead letter queues

Quando um consumidor falha repetidamente em processar um evento, ele deve enviar o evento para uma dead letter queue (DLQ) para inspeção manual em vez de bloquear o pipeline inteiro:

goif err := processEvent(record); err != nil {
    // Envia para DLQ para investigação manual
    dlqProducer.Send(record)
    // Commit offset para continuar processando outros eventos
    consumer.Commit(record)
}

Estratégias de otimização de performance

Dimensionamento de partition

Mais partitions habilitam mais paralelismo mas aumentam overhead:

  • Muito poucas partitions: Limita paralelismo de consumidor e cria hotspots.
  • Muitas partitions: Aumenta overhead de metadata de broker e pode causar tempestades de rebalancing.

Um ponto de partida prático: Número de partitions = Número de consumidores × Fator de paralelismo alvo (tipicamente 2-3x).

Batching e compressão

Kafka suporta batching de mensagens e compressão para reduzir overhead de rede:

properties# Batch messages antes de enviar
batch.size=16384
linger.ms=5

# Usa compressão (gzip, snappy, lz4, zstd)
compression.type=lz4

Compressão tipicamente fornece redução de 3-5x com overhead de CPU mínimo.

Semântica exactly-once

Kafka suporta processamento exactly-once usando transactions e produtores idempotentes:

properties# Habilita producer idempotente
enable.idempotence=true

# Usa transactions para exactly-once através de topics
isolation.level=read_committed

Isso elimina processamento duplicado mas requer design cuidadoso de schema e gerenciamento de limites de transaction.

Plano de implementação em 30 dias

  1. Identifique fontes de evento: Mapeie quais eventos de negócio são candidatos naturais para streaming.
  2. Desenhe schemas de evento: Defina schemas iniciais com compatibilidade backward em mente.
  3. Selecione modelo de deployment: Escolha entre Kafka self-hosted, Confluent Cloud ou serviços gerenciados.
  4. Implemente primeiros consumidores: Comece com consumidores de baixo risco (analytics, logging) para construir maturidade operacional.
  5. Adicione monitoramento: Deploy de monitoramento de lag de consumidor e alertas antes de rollout de produção.
  6. Documente modos de falha: Crie runbooks para cenários comuns de falha (crashes de consumidor, falhas de broker).

Checklist de validação de produção

Indicadores para acompanhar:

  • Lag de consumidor através de todos os consumer groups (deveria permanecer estável).
  • Latência end-to-end de evento (tempo da criação de evento até processamento).
  • Frequência e duração de rebalance (rebalances frequentes indicam instabilidade).
  • Taxa de dead letter queue (taxas altas indicam issues sistêmicos).

Decisões de plataforma para o próximo ciclo

  • Defina governança de schema de evento: quem aprova mudanças de schema e como são comunicadas?
  • Estabeleça políticas de retention: quanto tempo eventos devem ser retidos para cenários de replay?
  • Configure replication factors: equilibre entre durabilidade e custo de recursos.

Precisa de ajuda para projetar uma arquitetura event-driven que escale sem pesadelos operacionais? Falar sobre software personalizado com a Imperialis para projetar e implementar essa evolução.

Fontes

Leituras relacionadas