Onde a Arquitetura Começa a Rachar
O caos começa sempre igual: microserviços crescendo, mais eventos circulando, instâncias subindo no Kubernetes… e a fila vira gargalo. Não é falta de CPU. Não é Docker mal configurado. É escolha errada de ferramenta.
Vejo isso direto em equipes que tentam usar RabbitMQ como se fosse Kafka e vice-versa. Um é message broker transacional. O outro é event log distribuído. Forçar o encaixe errado vira over-engineering e gera mais incêndio do que solução.
Kafka para Volume, RabbitMQ para Controle: a Regra Pragmática
Sem rodeios:
- Kafka: throughput absurdo, histórico de eventos, reprocessamento natural, escalabilidade horizontal verdadeira.
- RabbitMQ: roteamento poderoso, entrega garantida, ack manual, backpressure real, sem a complexidade absurda do ecossistema Kafka.
O erro clássico: usar Kafka para workloads de baixa taxa mas alta necessidade de precisão e orquestração fina. Ou usar Rabbit para processar 1 milhão de eventos por minuto. Aí vira sofrimento.
Implementação de Senior: Configurando Consumidores de Forma Correta
Exemplo direto do campo: um consumidor resiliente e escalável usando Kafka (com backpressure controlado) e outro com RabbitMQ usando ack manual para evitar perda de mensagens.
Exemplo Kafka (Node.js + KafkaJS)
import { Kafka } from "kafkajs";
const kafka = new Kafka({ brokers: ["kafka1:9092"] });
const consumer = kafka.consumer({ groupId: "pedido-processamento" });
await consumer.connect();
await consumer.subscribe({ topic: "pedidos.criados", fromBeginning: false });
await consumer.run({
eachMessage: async ({ message }) => {
const payload = JSON.parse(message.value.toString());
try {
processPedido(payload);
} catch (err) {
console.error("Erro ao processar. Enviando para DLQ...", err);
await kafka.producer()
.send({ topic: "pedidos.dlq", messages: [{ value: message.value }] });
}
},
});
Exemplo RabbitMQ (Node.js + amqplib)
import amqp from "amqplib";
const conn = await amqp.connect("amqp://localhost");
const channel = await conn.createChannel();
await channel.assertQueue("pagamentos");
channel.prefetch(10); // backpressure real
channel.consume("pagamentos", async (msg) => {
try {
const payload = JSON.parse(msg.content.toString());
await processarPagamento(payload);
channel.ack(msg); // controle fino
} catch (err) {
console.error("Falha. Rejeitando mensagem.");
channel.nack(msg, false, false); // manda para DLQ
}
});
A Fatura Chega: O Custo de Cada Escolha
KAFKA
- Você ganha escala quase infinita…
- …mas paga com infra pesada: ZooKeeper (ou KRaft), storage abundante e tunning avançado.
- Excelente para eventos imutáveis, péssimo para workflows sensíveis.
RABBITMQ
- Controle granular de entrega, simplicidade operacional.
- Mas sharding é limitado, e ele sofre com throughput gigantesco.
- Se tentar empurrar 500k msgs/s, você vai queimar a mão.
Direto das Trincheiras
- Se precisa reprocessar eventos facilmente, nem pense: escolha Kafka.
- Se o negócio exige orquestração e idempotência precisa, RabbitMQ é mais seguro.
- Não suba Kafka para workloads pequenos — isso é over-engineering clássico de hype.
Fontes
Arquitetura de Software, Arquitetura de Soluções e System Design,
Blog | gaGO.io
Obrigado por acompanhar essa reflexão até o fim!
Espero que esses pontos ajudem você a tomar decisões mais lúcidas no seu próximo projeto. Não deixe de conferir outros artigos aqui no blog, onde descascamos outros hypes da nossa área.
Valeu e até a próxima! 😉


