Nesse artigo vou trazer um resumo sobre o Kafka. Sempre gosto de fazer resumos que podem me ajudar no dia a dia, afinal, é impossível lembrar de tudo o tempo todo.
- Fila, Tópico e Grupos
Apresenta o conceito de fila ou tópico (Pub/Sub):
Kafka -> fila -> Só tem um grupo, o primeiro nó do grupo que ler trata a mensagem.
'--> tópico -> a mesma mensagem pra vários grupos, onde em cada grupo o primeiro nó que pegar lê e trata a mensagem (Pub/Sub).
Vamos ver o coneito de grupo no exemplo abaixo:
@KafkaListener(
topics = "pedidos",
groupId = "pagamento-service"
)
public void consumir(Pedido pedido) {
}
Se o microsserviço A é do grupo "pagamento-service" e apenas esse grupo acessa o tópico "pedidos", é uma fila. Pode ter várias instancias de A que não impacta nesse comportamento de fila.
Se crio o microsserviço B e ele tem a seguinte definição de grupo: groupId = "estoque-service"
@KafkaListener(
topics = "pedidos",
groupId = "estoque-service"
)
public void consumir(Pedido pedido) {
}
Então agora temos o comportamento de Pub/Sub (tópico), porque o grupo "estoque-service" também acessa "pedido".
*Note que há um overhead de conceitos aí na questão de tópico, uma coisa é o tópic do Kafka e outra é o conceito de tópico no sentido de Pub/Sub, onde alguém publica e outros são (sub)inscritos para receber a mensagem.
Usando mensagens diferentes no mesmo tópico
Embora pareça estranho, usar mensagens diferentes no mesmo tópico não é errado. É assim por exemplo que se garante a ordem de execução, usando a mesma key (vamos ver esse coneito mais a frente) e tópico o que joga na mesma partição (vamos ver esse coneito mais a frente), mas o corpo da mensagem é diferente, e cada consumer que tem seu group-id consome o que lhe interessa e descarta o resto. Ignorar evento NÃO é erro.
Exemplo: Podemos ter o Tópico: pedidos e usar a key = pedidoId
Eventos (Cada evento é uma mensagem diferente, com campos diferente):
- PEDIDO_CRIADO
- PEDIDO_PAGO
- PEDIDO_ENVIADO
- PEDIDO_CANCELADO
Isso casa perfeitamente com Event Sourcing, DDD, CQRS, Auditoria, Reprocessamento...
Por que usar o MESMO tópico nesse caso? Porque você quer garantir:
✔️ Ordem dos eventos do pedido
✔️ Processamento sequencial
✔️ Consistência de estado
✔️ Um único consumer por pedido
✔️ Reprocessamento confiável
- Partições:
Partições -> paralelismo/escalabilidade. São divisões dentro de um tópico. Cada partição permite apenas um consumidor por grupo. Se tiver mais consumidores que partições de um mesmo grupo eles ficam ociosos.
Partição NÃO é algo que você “escala dinamicamente” como pod de Kubernetes. Partição é uma decisão estrutural, onde alterar depois tem efeitos colaterais
Kafka foi desenhado para escalar consumidores, mas com partições pensadas antes. Ao alterar partições, as partições novas começam vazias, as chaves (keys) podem ir para partições diferentes, a ordem global não é preservada, pode quebrar a lógica baseada em key.
👉 Por isso: erramos para mais, não para menos. Partições devem acompanhar o pico de consumo esperado, não o consumo médio.
- Keys
As Keys servem para decidir em qual partição a mensagem vai cair. Mesma key significa que a mensagem sempre vai cair na mesma partição. Isso é importante porque o Kafka só garante ordem dentro da partição.
Quando usar key:
✔️ Existe uma entidade de negócio
✔️ Eventos precisam ser processados em ordem
✔️ Existe estado
✔️ Existe atualização incremental
Quando NÃO usar key:
❌ Eventos são independentes
❌ Não existe estado
❌ Ordem não importa
❌ Quer máximo throughput
Keys influenciam na escalabilidade (trade-off real)
Quanto mais granular a key:
- Mais espalhamento
- Mais paralelismo
- Menos ordem global
Quanto mais concentrada a key:
- Menos paralelismo
- Mais ordem
- Possível gargalo
Exemplo de chave ruim: key = "PEDIDOS" -> Tudo cai em uma partição só e o Kafka vira single-thread.
Exemplo de chave boa: pedidoId, userId, contaId, CPF, CNPJ...
Quando se trabalha com Keys e é necessário aumentar partições, a mesma key pode ir para partições diferentes no momento dessa alteração e a ordem não será garantida. Isso acontece porque o calculo de pra qual partição a mensagem vai é: "hash(key) % N" onde N é o número de partições. Por isso sistemas que dependem de key precisam pensar bem antes de aumentar partições. É preciso fazer uma análise dos riscos.
Comando para criar um tópico em Kafka:
./kafka-topics.sh --create --topic <nome_do_topico> --bootstrap-server <endereco_do_broker> --partitions <numero_de_particoes> --replication-factor <fator_de_replicacao>

