Message brokers: RabbitMQ vs Kafka
1. Introdução aos Message Brokers na Arquitetura de Software
Em arquiteturas de microsserviços, o desacoplamento entre componentes é essencial para escalabilidade e evolução independente. Message brokers atuam como intermediários confiáveis, permitindo que produtores e consumidores troquem informações sem dependência direta. O modelo de entrega define o comportamento do sistema: filas tradicionais garantem que cada mensagem seja processada por um único consumidor, enquanto streams de eventos permitem que múltiplos consumidores leiam o mesmo fluxo de dados.
RabbitMQ e Kafka são os brokers mais adotados, mas partem de filosofias distintas. A escolha entre eles depende de critérios como padrão de comunicação, requisitos de latência, volume de dados e necessidades de replay histórico.
2. RabbitMQ: Arquitetura e Modelo de Mensageria
RabbitMQ implementa o protocolo AMQP 0-9-1 e organiza o roteamento através do conceito de exchanges. Uma exchange recebe mensagens dos produtores e as distribui para filas com base em regras de binding. Os tipos de exchange oferecem flexibilidade:
- Direct: roteia mensagens para filas cuja routing key corresponde exatamente.
- Topic: permite correspondência por padrões (ex:
pedidos.criado.*). - Fanout: envia cópia da mensagem para todas as filas vinculadas.
- Headers: roteia baseado em atributos do cabeçalho, não na routing key.
O modelo de entrega é push-based: o broker envia mensagens ativamente aos consumidores assim que disponíveis. Confirmações manuais (ack) garantem processamento seguro, e dead letter queues (DLQ) capturam mensagens que falharam repetidamente.
Exemplo de configuração de exchange e fila em RabbitMQ:
# Declaração de exchange do tipo topic
channel.exchange_declare(exchange='pedidos', exchange_type='topic')
# Declaração de fila com DLQ
channel.queue_declare(queue='processar_pedidos',
arguments={
'x-dead-letter-exchange': 'pedidos_dlq',
'x-dead-letter-routing-key': 'falha'
})
# Binding da fila à exchange
channel.queue_bind(exchange='pedidos',
queue='processar_pedidos',
routing_key='pedido.criado.#')
Casos típicos incluem tarefas assíncronas (envio de e-mails), RPC com filas de resposta e balanceamento de carga entre workers concorrentes.
3. Kafka: Arquitetura e Modelo de Stream de Eventos
Kafka foi projetado como um log distribuído imutável. Mensagens são organizadas em tópicos, que são particionados para escalabilidade horizontal. Cada partição é um log sequencial, e mensagens recebem um offset único. Consumidores trabalham em grupos, onde cada partição é atribuída a um único consumidor do grupo.
O modelo de consumo é pull-based: consumidores solicitam mensagens quando estão prontos, controlando sua própria taxa de processamento. O rebalanceamento ocorre quando consumidores entram ou saem do grupo, redistribuindo partições.
Exemplo de produtor e consumidor em Kafka:
# Produtor enviando mensagem
producer = KafkaProducer(bootstrap_servers='localhost:9092')
producer.send('pedidos', key=b'123', value=b'{"id": 1, "status": "criado"}')
# Consumidor em grupo
consumer = KafkaConsumer('pedidos',
group_id='processadores',
bootstrap_servers='localhost:9092',
auto_offset_reset='earliest')
for msg in consumer:
processar(msg.value)
A retenção configurável (por tempo ou tamanho) permite replay de eventos históricos, fundamental para event sourcing e auditoria.
4. Comparação de Desempenho e Escalabilidade
Kafka é otimizado para alta vazão: pode processar milhões de mensagens por segundo em clusters modestos, graças ao particionamento nativo e ao uso eficiente de I/O sequencial em disco. RabbitMQ oferece baixa latência (microssegundos) para cenários com milhares de mensagens por segundo, mas o throughput máximo é inferior.
A escalabilidade do Kafka é horizontal por design: adicionar partições aumenta a capacidade paralela de consumo. RabbitMQ escala via clustering, mas com complexidade adicional e limites práticos no número de nós.
Em persistência, RabbitMQ oferece mensagens transitórias (memória) ou persistentes (disco). Kafka persiste todas as mensagens por padrão, sacrificando latência em troca de durabilidade.
Comparação de configurações típicas:
RabbitMQ (alta segurança):
- delivery_mode=2 (persistente)
- mandatory=true (confirmação de rota)
- publisher_confirms=true
Kafka (alta performance):
- acks=1 (apenas líder confirma)
- compression.type=snappy
- batch.size=16384
5. Garantias de Entrega e Confiabilidade
Ambos suportam at-least-once (padrão), at-most-once e exactly-once. RabbitMQ alcança exactly-once combinando confirmações do publisher, transações e deduplicação no consumidor. Kafka oferece exactly-once semântico nativo desde a versão 0.11, através de transações e idempotência do produtor.
Para falhas, RabbitMQ move mensagens rejeitadas para DLQ configuradas por fila. Kafka depende de retentativas no produtor e consumidores idempotentes, sem DLQ nativa (embora possa ser implementada com tópicos separados).
A ordenação é garantida por fila no RabbitMQ e por partição no Kafka. Para ordenação global, RabbitMQ exige fila única (limitando paralelismo), enquanto Kafka exige partição única (mesma limitação).
6. Padrões de Integração e Ecossistema
RabbitMQ utiliza AMQP, protocolo maduro suportado por diversas linguagens. Seu ecossistema inclui plugins para MQTT, STOMP e integração com sistemas legados via JMS. É ideal para cenários onde roteamento flexível e protocolos heterogêneos são necessários.
Kafka oferece Kafka Connect para integração com bancos de dados e sistemas externos, e Kafka Streams para processamento de streams diretamente na JVM. O ecossistema é forte em data pipelines, ETL e plataformas de eventos.
Em arquiteturas híbridas, RabbitMQ pode atuar como gateway para requisições síncronas e tarefas curtas, enquanto Kafka gerencia streams de eventos de longa duração e auditoria.
Exemplo de arquitetura híbrida:
[API Gateway] -> [RabbitMQ] -> [Microsserviço A] -> [Kafka] -> [Data Lake]
|
v
[Microsserviço B]
7. Guia de Decisão e Boas Práticas
Escolha RabbitMQ quando:
- Necessita de roteamento complexo (topic, headers)
- Requer baixa latência (< 10ms)
- Precisa de filas temporárias ou RPC
- Sistema legado com AMQP/JMS
Escolha Kafka quando:
- Volume alto (> 100k msg/s)
- Necessita de replay histórico
- Implementa event sourcing ou CQRS
- Precisa de integração com big data (Hadoop, Spark)
Considerações operacionais:
- Monitore RabbitMQ com plugin de gestão e Prometheus
- Para Kafka, use Cruise Control para balanceamento de partições
- Versionamento de esquemas: Schema Registry (Kafka) ou cabeçalhos AMQP (RabbitMQ)
- Custos: RabbitMQ consome menos recursos em baixa escala; Kafka requer mais nós para replicação
Referências
- RabbitMQ Official Documentation — Documentação completa do RabbitMQ, incluindo exchanges, filas e protocolo AMQP
- Apache Kafka Documentation — Guia oficial do Kafka com detalhes sobre tópicos, partições e configurações
- RabbitMQ vs Kafka: An Architect's Dilemma (Confluent Blog) — Artigo técnico comparando casos de uso e trade-offs arquiteturais
- Understanding Message Brokers (AWS Whitepaper) — Visão geral sobre brokers em arquitetura de microsserviços
- Kafka vs RabbitMQ: Performance Benchmark (CloudAMQP) — Benchmarks práticos comparando throughput e latência em cenários reais