.NET Mensageria RabbitMQ Kafka Microsserviços Arquitetura

RabbitMQ vs Kafka vs Azure Service Bus: escolhendo o message broker certo

Comparativo completo entre RabbitMQ, Apache Kafka e Azure Service Bus para arquiteturas .NET: quando usar cada um, diferenças de modelo.

N
Neryx Digital Architects
13 de março de 2026
14 min de leitura
230 profissionais leram
Categoria: Arquitetura Público: Times de engenharia e produto Etapa: Aprendizado

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.

Precisa desenhar a próxima fase com menos retrabalho?

Fazemos discovery técnico para mapear riscos, arquitetura-alvo e sequência de execução antes de investir pesado.

Solicitar Discovery

Newsletter

Receba artigos como este no seu e-mail

Conteúdo técnico sobre arquitetura de software, .NET, IA e gestão de produto. Sem spam.