Tecnologias/05 - Comparações5 min
Kafka vs Fila Tradicional
Conceito
A diferença cabe numa frase:
Fila entrega e apaga. Log guarda e marca a posição de quem leu.
Todo o resto é consequência. Numa fila, a mensagem é um trabalho que sai da fila quando alguém o faz. Num log, a mensagem é um fato que fica registrado, e cada leitor carrega seu próprio marcador.
FILA (RabbitMQ, SQS) LOG (Kafka, Kinesis)
┌───┬───┬───┬───┐ [0][1][2][3][4][5][6]
│ m │ m │ m │ m │ → consumidor ↑ ↑
└───┴───┴───┴───┘ (mensagem sai) grupo B grupo A
(nada é apagado ao ler)
Lado a lado
| Kafka | RabbitMQ | SQS | Kinesis | |
|---|---|---|---|---|
| Modelo | log particionado | broker AMQP | fila gerenciada | log gerenciado |
| Após consumo | permanece | apagada | apagada | permanece |
| Retenção | dias–meses (ou infinita com tiered) | até o ack | até 14 dias | 24 h–365 dias |
| Replay | sim | não | não | sim |
| Ordem | por partição | por fila (com 1 consumidor) | FIFO só em fila FIFO | por shard |
| Ack | por offset (+ por mensagem em share group) | por mensagem | por mensagem | por posição |
| Roteamento | por tópico e chave | rico (exchange, binding, headers) | simples | por tópico |
| Prioridade | não | sim | não | não |
| Delay / agendamento | não (fora de plugins/tópicos de retry) | plugin | sim (até 15 min) | não |
| Fan-out | grupos independentes | exchange fanout | via SNS | consumidores independentes |
| Throughput típico | milhões/s | dezenas de milhares/s | alto (gerenciado) | alto |
| Latência mínima | ms | sub-ms | dezenas de ms | ~200 ms (ou EFO) |
| Esforço operacional | alto (ou gerenciado) | médio | zero | baixo |
| Custo | infra/licença | infra | por requisição | por shard/hora |
O critério de escolha
Quatro perguntas, na ordem em que devem ser feitas:
1. Vou precisar reler o passado? Reprocessar depois de um bug, alimentar um sistema novo com o histórico, refazer uma agregação. Se sim → log (Kafka/Kinesis). Fila não tem para onde voltar.
2. Vários consumidores precisam do mesmo dado, de forma independente? Se sim → log, ou fila + fan-out explícito (SNS→SQS, exchange do Rabbit). No log é nativo e cada consumidor tem seu ritmo.
3. Preciso de ack individual, prioridade, delay ou roteamento por conteúdo? Se sim → broker de fila (RabbitMQ é o mais rico nisso). No Kafka isso era desconfortável até os share groups do 4.2.
4. Quantas mensagens por segundo, de verdade?
Abaixo de alguns milhares/s, praticamente qualquer coisa serve — inclusive
SELECT ... FOR UPDATE SKIP LOCKED no Postgres que você já opera.
Essa opção deveria ser considerada com muito mais frequência do que é.
Os share groups (KIP-932), GA em fev/2026, dão ao Kafka ack por mensagem, redelivery e paralelismo desacoplado do número de partições — ou seja, semântica de fila dentro do log. Isso não apaga a diferença (roteamento rico, prioridade e delay continuam sendo do RabbitMQ), mas enfraquece o argumento "Kafka não serve para fila de trabalho". Ver 3. Partições, Offsets e Consumer Groups.
O equivalente na AWS
| Preciso de… | Serviço |
|---|---|
| Fila de trabalho simples | SQS (Standard ou FIFO) |
| Fan-out de notificação | SNS (+ SQS por consumidor) |
| Roteamento por conteúdo, integração SaaS | EventBridge |
| Log com replay | Kinesis Data Streams |
| Kafka gerenciado | Amazon MSK |
Vale ler Cheatsheet Mensageria e 07 - MOC Desacoplamento e Integração para o recorte de certificação.
Trade-offs
Log te dá replay e cobra em disco e disciplina. Guardar 30 dias de eventos é armazenamento real, e o "podemos reprocessar" só é verdade se os consumidores forem idempotentes (4. Garantias de Entrega e Idempotência) e o schema for versionado — mensagem de 3 semanas atrás está no formato de 3 semanas atrás.
Fila te dá simplicidade e joga o histórico fora. Quando alguém pedir "reprocesse os pedidos de ontem porque o cálculo estava errado", a resposta é: não dá. Esse pedido chega em todo sistema, cedo ou tarde.
O erro caro não é escolher a ferramenta errada — é escolher a categoria errada. Kafka usado como fila de trabalho gera frustração diária (rebalance, offsets, uma mensagem ruim travando a partição). SQS usado como log gera um projeto de migração no dia em que o replay for necessário.
O trade-off central: fila otimiza para executar trabalho agora; log otimiza para preservar fatos. As duas coisas parecem "mandar mensagem" e têm requisitos opostos de retenção, ordem e ack. Decida qual das duas você tem antes de escolher o produto.
Exemplo prático
O mesmo domínio, com as duas ferramentas no desenho — porque a resposta madura é frequentemente "as duas":
┌─ Kafka: pedidos.eventos (retenção 30 dias) ─┐
POST /pedidos │ │
→ Postgres (outbox) ─┤ grupo "faturamento" → nota fiscal │
→ 201 │ grupo "estoque" → reserva │
│ grupo "analytics" → data lake │
│ grupo "recomendação" → treina modelo │
└──────────────────────────────────────────────┘
│
└→ SQS "emails" ─→ worker de e-mail
(delay 5 min, DLQ, retry por mensagem)
Por que Kafka nos eventos: quatro consumidores independentes do mesmo fato; o time de dados quer reprocessar 30 dias quando muda uma regra; ordem por pedido importa.
Por que SQS no e-mail: é trabalho, não fato. Você quer delay de 5 minutos ("não mande o e-mail se o pedido for cancelado em seguida"), retry com backoff por mensagem e DLQ — tudo que uma fila faz nativamente e um log não faz bem. Ninguém vai querer "reprocessar os e-mails de ontem".
E a opção que resolve o começo de quase todo projeto, sem broker nenhum:
-- Fila no banco que você já tem. Aguenta milhares de jobs/s.
SELECT id, payload FROM jobs
WHERE status = 'pendente' AND disponivel_em <= now()
ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 10;
Zero infraestrutura nova, transação junto com o dado do domínio (nada de outbox!), e
observabilidade com SELECT count(*). Ver 1. PostgreSQL e Task Queues.
Uma fila em banco pode atender tarefas próximas dos dados transacionais. SQS ou RabbitMQ podem oferecer isolamento operacional e mecanismos próprios de entrega. Kafka pode atender retenção, replay e consumo independente. Essa não é uma sequência obrigatória: volume, garantias e capacidade operacional determinam a escolha.
Aprofundamento aplicado
Escolher pelo ciclo de vida do dado
Um comando como “gerar relatório 42” pede execução com acompanhamento de tentativa e resultado. Um fato como “pedido 42 foi pago” pode alimentar consumidores independentes e reconstruções futuras. O sistema pode precisar dos dois padrões na mesma arquitetura.
A comparação deve declarar o mecanismo: consumer groups tradicionais do Kafka, share groups, filas RabbitMQ ou streams RabbitMQ possuem semânticas diferentes. Nome do produto sozinho não descreve ack, ordem e retenção.
Critérios que podem justificar a decisão
| Necessidade | Pergunta de verificação |
|---|---|
| Replay | Por quanto tempo e para quais consumidores? |
| Ordem | Global, por entidade ou dispensável? |
| Trabalho demorado | Como controlar posse, prazo e reentrega? |
| Vários interessados | Cada um precisa receber todo evento? |
| Roteamento | Quais regras escolhem destinos? |
| Falha no destino | Como limitar retry e recuperar mensagens? |
Exercício: projete envio de e-mail e reconstrução de um painel a partir dos pagamentos. Resultado esperado: justifique retenção e consumo de cada fluxo. Não existe número universal de consumidores a partir do qual Kafka se torna necessário; use requisitos de replay, volume, operação e garantias.
Referências: design do Kafka e filas RabbitMQ.
Relacionado
Parte de MOC Comparações · kafka.apache.org · Kafka 4.2.0