Message brokers são a cola de arquiteturas de microsserviços — sem eles, serviços precisam se conhecer diretamente, falhas cascateiam e escalabilidade fica travada em chamadas síncronas. O problema é que RabbitMQ, Kafka e Azure Service Bus têm modelos fundamentalmente diferentes, e escolher o errado custa caro para desfazer. Este guia vai direto ao ponto: o que cada um resolve melhor e quando cada escolha é um erro.
Modelos de entrega: a diferença que muda tudo
Antes de comparar features, entenda os modelos:
RabbitMQ — message queue tradicional: Uma mensagem é publicada em uma exchange, roteada para filas, e consumida por um consumer. A mensagem some após o consumo bem-sucedido. O broker garante entrega para um consumer (por padrão). Analogia: caixa postal — você entrega uma carta, alguém retira, a carta some.
Kafka — log distribuído: Mensagens são escritas em um log imutável particionado. Cada consumer group lê o log de forma independente — múltiplos sistemas podem consumir a mesma mensagem. As mensagens ficam no log por um tempo configurável (dias, semanas). Analogia: YouTube — um vídeo publicado pode ser assistido por milhões de viewers independentes, e você pode voltar para assistir de novo.
Azure Service Bus — fila gerenciada na nuvem: Similar ao RabbitMQ no modelo (fila ou tópico com assinaturas), mas totalmente gerenciado na Azure. Sem infra para operar, integrado com Azure AD, suporte nativo a sessões, dead-letter automático. Analogia: RabbitMQ as a Service com SLA da Microsoft.
RabbitMQ: quando é a escolha certa
RabbitMQ brilha em cenários de task queue — você tem trabalho a fazer, quer distribuir entre workers, e não precisa histórico das mensagens após o processamento:
// MassTransit com RabbitMQ — consumer simples
public class ProcessarPedidoConsumer : IConsumer<ProcessarPedidoCommand>
{
private readonly IPedidoService _service;
public ProcessarPedidoConsumer(IPedidoService service)
=> _service = service;
public async Task Consume(ConsumeContext<ProcessarPedidoCommand> context)
{
await _service.ProcessarAsync(context.Message.PedidoId);
// Mensagem é confirmada (ack) automaticamente se não lançar exceção
// Se lançar, MassTransit faz retry e eventualmente manda para DLQ
}
}
// Registro em Program.cs
builder.Services.AddMassTransit(x =>
{
x.AddConsumer<ProcessarPedidoConsumer>();
x.UsingRabbitMq((ctx, cfg) =>
{
cfg.Host("localhost", "/", h => {
h.Username("guest");
h.Password("guest");
});
cfg.ConfigureEndpoints(ctx);
});
});
Use RabbitMQ quando: você quer processar tarefas em background (enviar e-mail, gerar PDF, processar imagem), precisa de roteamento flexível por exchange/binding, quer garantia de que exatamente um worker processa cada mensagem, ou precisa de filas com prioridade. É fácil de hospedar, consome pouca memória, e a curva de aprendizado é suave.
Não use quando: múltiplos sistemas precisam consumir o mesmo evento de forma independente, você precisa de replay (reprocessar mensagens antigas), ou volume é tão alto que a persistência no banco (DETS) vira gargalo.
Kafka: quando o log distribuído faz sentido
Kafka é a escolha quando mensagens são eventos que múltiplos sistemas precisam observar, e você precisa de throughput alto ou a capacidade de reprocessar o histórico:
// Confluent.Kafka — producer de baixo nível
public class PedidoCriadoProducer
{
private readonly IProducer<string, PedidoCriadoEvent> _producer;
public PedidoCriadoProducer(IProducer<string, PedidoCriadoEvent> producer)
=> _producer = producer;
public async Task PublicarAsync(PedidoCriadoEvent evento)
{
await _producer.ProduceAsync(
topic: "pedidos-criados",
message: new Message<string, PedidoCriadoEvent>
{
// Usar o ID do pedido como key = mensagens do mesmo pedido vão para a mesma partição
// Garante ordering por pedido, sem ordering global (que escala mal)
Key = evento.PedidoId.ToString(),
Value = evento
});
}
}
// Consumer com confluent.kafka
public class NotificacaoConsumer : BackgroundService
{
private readonly IConsumer<string, PedidoCriadoEvent> _consumer;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_consumer.Subscribe("pedidos-criados");
while (!stoppingToken.IsCancellationRequested)
{
try
{
var result = _consumer.Consume(stoppingToken);
await ProcessarNotificacaoAsync(result.Message.Value);
// Commit manual do offset — você controla o que foi processado
_consumer.Commit(result);
}
catch (ConsumeException e)
{
_logger.LogError(e, "Erro ao consumir mensagem");
}
}
}
}
Use Kafka quando: você precisa de event sourcing ou auditoria completa de eventos, múltiplos sistemas consomem o mesmo evento de forma independente (serviço de notificação, analytics e estoque lendo o mesmo evento "pedido criado"), throughput é massivo (>100k mensagens/segundo), ou você precisa reprocessar eventos históricos (migração de dados, reconstrução de estado, debug).
Não use quando: você precisa de roteamento complexo por conteúdo, cada mensagem deve ser processada por exatamente um consumer (Kafka não garante isso nativamente — precisa de consumer groups bem configurados), ou sua equipe não tem experiência para operar um cluster Kafka (complexidade operacional é real).
Azure Service Bus: quando managed service é o caminho
Azure Service Bus remove toda a complexidade operacional. É RabbitMQ-like no modelo, mas com SLA de 99.9%, georredundância, e integração nativa com o ecossistema Azure:
// Azure.Messaging.ServiceBus — producer
public class PedidoService
{
private readonly ServiceBusSender _sender;
public PedidoService(ServiceBusClient client)
=> _sender = client.CreateSender("pedidos");
public async Task CriarPedidoAsync(CriarPedidoDto dto, CancellationToken ct)
{
var pedido = await _repository.CriarAsync(dto, ct);
// Agendamento: processa em 30 minutos (ex: cancelamento automático)
var mensagem = new ServiceBusMessage(JsonSerializer.Serialize(new
{
pedido.Id,
pedido.ClienteId,
CriadoEm = DateTime.UtcNow
}))
{
MessageId = pedido.Id.ToString(), // Deduplicação nativa
SessionId = pedido.ClienteId.ToString(), // Ordering por cliente
};
await _sender.SendMessageAsync(mensagem, ct);
}
}
// Registro com Managed Identity (sem senha no código)
builder.Services.AddSingleton(provider =>
new ServiceBusClient(
fullyQualifiedNamespace: "meu-bus.servicebus.windows.net",
credential: new DefaultAzureCredential())); // Managed Identity
Use Azure Service Bus quando: você já está na Azure e quer evitar gerenciar infra de broker, precisa de sessões (ordering garantido por cliente/entidade), quer dead-letter automático com inspeção pelo portal, precisa de deduplicação nativa por MessageId, ou o orçamento para ops é limitado (SaaS é mais barato em equipes pequenas que hospedar RabbitMQ com HA).
Comparativo direto
// Critério por critério
| Critério | RabbitMQ | Kafka | Azure Service Bus |
|-----------------------|----------------|--------------------|--------------------|
| Modelo | Queue/Pub-Sub | Log distribuído | Queue/Topic |
| Múltiplos consumers | Por binding | Nativo (offset) | Por assinatura |
| Replay de eventos | ❌ Não | ✅ Sim | ❌ Não |
| Throughput | Alto (~50k/s) | Muito alto (>1M/s) | Alto (~10k/s) |
| Ordering garantido | Por fila | Por partição+key | Por sessão |
| Operação | Você gerencia | Você gerencia | Managed (Azure) |
| Curva de aprendizado | Baixa | Alta | Baixa |
| Custo (cloud) | ~$30-100/mês | ~$300-1000/mês | Pay-per-use |
| Multi-cloud/on-prem | ✅ Sim | ✅ Sim | ❌ Só Azure |
| MassTransit suporte | ✅ Nativo | ✅ Nativo | ✅ Nativo |
Padrão híbrido: RabbitMQ para tasks, Kafka para eventos
Em sistemas maiores, a resposta não é escolher um — é usar cada um para o que foi feito:
// Arquitetura híbrida comum:
// Kafka: domain events de alta importância
// "Pedido criado" → consumido por Notificações, Analytics, Estoque, Fiscal
// Replay possível → migração de dados sem perda
kafka.Publish("pedidos-criados", pedidoCriadoEvent);
// RabbitMQ: tasks de processamento
// "Processar pagamento" → processado por exatamente um worker
// "Enviar e-mail de confirmação" → task point-to-point
rabbitMq.Send("processar-pagamento-queue", processarPagamentoCommand);
// Azure Service Bus: integração com sistemas externos na Azure
// "Sincronia com ERP" → ordering por empresa, dead-letter, deduplicação
serviceBus.Send("erp-sync", syncCommand, sessionId: empresaId);
Checklist de decisão
Antes de escolher, responda:
1. Múltiplos sistemas precisam reagir ao mesmo evento? Sim → Kafka ou Service Bus Topics. Não → RabbitMQ é suficiente.
2. Você precisa reprocessar eventos históricos? Sim → Kafka obrigatório. Não → qualquer um.
3. Você opera na Azure e quer zero infra? Sim → Azure Service Bus. Não → RabbitMQ ou Kafka self-hosted.
4. Throughput esperado é acima de 50k mensagens/segundo? Sim → Kafka. Não → RabbitMQ ou Service Bus.
5. Você tem expertise para operar Kafka? Não → use Confluent Cloud (Kafka managed) ou evite Kafka. Kafka auto-hospedado mal configurado é um problema de produção esperando para acontecer.
A escolha errada aqui não é catastrófica imediatamente — você consegue funcionar com qualquer um nos primeiros meses. O problema aparece quando você precisa do que não escolheu: replay de eventos em RabbitMQ, operação simples em Kafka, multi-cloud em Service Bus. Escolher bem no início evita uma migração dolorosa depois.