Cloud e plataforma

Guia de Seleção de Fila de Mensagens 2026: Kafka vs RabbitMQ vs Redis Streams vs SQS

O broker de mensagens certo depende do seu caso de uso, requisitos de escala e capacidades da equipe. Aqui está uma comparação prática para tomar uma decisão informada.

10/03/20268 min de leituraCloud
Guia de Seleção de Fila de Mensagens 2026: Kafka vs RabbitMQ vs Redis Streams vs SQS

Resumo executivo

O broker de mensagens certo depende do seu caso de uso, requisitos de escala e capacidades da equipe. Aqui está uma comparação prática para tomar uma decisão informada.

Ultima atualizacao: 10/03/2026

Resumo executivo

Filas de mensagens são a espinha dorsal de arquiteturas de microserviços assíncronas, permitindo desacoplamento, escalabilidade e tolerância a falhas. Mas nem todos os brokers de mensagens resolvem o mesmo problema. Kafka, RabbitMQ, Redis Streams e Amazon SQS têm pontos fortes distintos, trade-offs e requisitos operacionais.

Escolher o broker de mensagens errado leva a frustração arquitetural: complexidade do Kafka para workloads simples, limites de throughput do RabbitMQ para streaming de eventos de alto volume, limitações de persistência do Redis Streams para dados críticos, ou lock-in de nuvem do SQS para implantações multi-cloud.

Este guia fornece um framework prático para selecionar o broker de mensagens certo baseado em seus requisitos específicos.

Matriz de comparação: Características principais

CaracterísticaApache KafkaRabbitMQRedis StreamsAmazon SQS
Modelo de MensagemStreams baseados em logFila + ExchangeStreams baseados em logFila
OrdenaçãoOrdenação por partiçãoOrdenação por filaOrdenação por streamMelhor esforço
EntregaPelo menos uma vezConfigurávelPelo menos uma vezPelo menos uma vez
PersistênciaBaseado em disco (configurável)Baseado em disco (configurável)Baseado em memória (AOF opcional)Baseado em disco
ThroughputMuito alto (milhões/seg)Alto (milhares/seg)Alto (milhares/seg)Alto (ilimitado)
Latência2-10ms1-5ms<1ms10-100ms
EscalabilidadeHorizontalVertical + ClusteringVerticalHorizontal (gerenciado)
ComplexidadeAltaMédiaBaixaMuito Baixa
Overhead OperacionalAltoMédioBaixoNenhum (gerenciado)
Cloud Lock-inNenhumNenhumNenhumAWS
Adequação de Caso de UsoStreaming de eventos, alto volumePropósito geral, roteamentoWorkloads simples, cachingNativo AWS, baixa ops

Apache Kafka: Streaming de eventos em escala

Arquitetura e pontos fortes

Kafka é um log distribuído, particionado e replicado otimizado para streaming de eventos de alto throughput. Armazena mensagens em tópicos divididos em partições, permitindo consumo paralelo.

Quando Kafka é a escolha certa:

  1. Streaming de eventos de alto volume
  • Milhões de mensagens por segundo
  • Múltiplos consumidores lendo os mesmos dados
  • Requisitos de event sourcing e replay
  1. Pipelines de dados em tempo real
  • Processamento de stream (Kafka Streams, ksqlDB)
  • Agregação de logs e monitoramento
  • Ingestão de dados IoT
  1. Armazenamento durável de eventos
  • Necessidade de replay eventos de posições arbitrárias
  • Requisitos de retenção de longo prazo (dias a semanas)

Exemplo de implementação Kafka:

typescript// Implementação de produtor Kafka
import { Kafka, Producer, ProducerRecord } from 'kafkajs';

class KafkaEventProducer {
  private producer: Producer;
  private topic: string;

  constructor(
    brokers: string[],
    clientId: string,
    topic: string
  ) {
    const kafka = new Kafka({
      clientId,
      brokers,
      retry: {
        initialRetryTime: 100,
        retries: 8
      }
    });

    this.producer = kafka.producer();
    this.topic = topic;

    this.producer.connect().catch(console.error);
  }

  async sendEvent(key: string, value: any): Promise<void> {
    const record: ProducerRecord = {
      topic: this.topic,
      messages: [
        {
          key,
          value: JSON.stringify(value),
          timestamp: Date.now()
        }
      ]
    };

    try {
      await this.producer.send(record);
      console.log(`Evento enviado para ${this.topic}:`, key);
    } catch (error) {
      console.error('Falha ao enviar evento:', error);
      throw error;
    }
  }

  async disconnect(): Promise<void> {
    await this.producer.disconnect();
  }
}

// Implementação de consumidor Kafka
class KafkaEventConsumer {
  private consumer: any;
  private topic: string;
  private groupId: string;

  constructor(
    brokers: string[],
    clientId: string,
    groupId: string,
    topic: string,
    private messageHandler: MessageHandler
  ) {
    const kafka = new Kafka({
      clientId,
      brokers,
      groupId
    });

    this.consumer = kafka.consumer({ groupId });
    this.topic = topic;
    this.groupId = groupId;
  }

  async start(): Promise<void> {
    await this.consumer.subscribe({ topic: this.topic, fromBeginning: false });

    await this.consumer.run({
      eachMessage: async ({ topic, partition, message }) => {
        try {
          const key = message.key?.toString();
          const value = JSON.parse(message.value?.toString() || '{}');

          console.log(`Processando mensagem de ${topic}[${partition}]:`, key);

          await this.messageHandler(key, value);

          // Commit é automático com eachBatchAutoCommit
        } catch (error) {
          console.error('Falha ao processar mensagem:', error);
          // Mensagem será reentregue devido a erro
        }
      }
    });
  }

  async stop(): Promise<void> {
    await this.consumer.disconnect();
  }
}

Considerações operacionais Kafka:

yaml# Configuração Kafka para produção
kafka:
  num.partitions: 12  # Aumentar para paralelismo
  default.replication.factor: 3  # Alta disponibilidade
  min.insync.replicas: 2  # Garantia de durabilidade
  auto.create.topics.enable: false  # Segurança
  log.retention.hours: 168  # 7 dias de retenção
  log.segment.bytes: 1073741824  # Segmentos de 1GB
  log.retention.check.interval.ms: 300000  # 5 minutos

zookeeper:
  tickTime: 2000
  initLimit: 10
  syncLimit: 5

Trade-offs do Kafka:

Prós:

  • Excelente throughput e escalabilidade
  • Particionamento e replicação integrados
  • Fortes garantias de ordenação por partição
  • Retenção de longo prazo de mensagens
  • Ecossistema rico (Kafka Connect, Streams)

Contras:

  • Alta complexidade operacional
  • Curva de aprendizado íngreme
  • Intensivo em recursos (requer Zookeeper/KRaft)
  • Não ideal para casos de uso simples de fila
  • Configuração complexa para alta disponibilidade

RabbitMQ: Broker de propósito geral rico em recursos

Arquitetura e pontos fortes

RabbitMQ é um broker de mensagens tradicional com exchanges, filas e bindings. Suporta padrões de roteamento flexíveis e múltiplos protocolos de mensagens (AMQP, MQTT, STOMP).

Quando RabbitMQ é a escolha certa:

  1. Mensagens de propósito geral
  • Work queues, publish-subscribe
  • Padrões request-reply
  • Múltiplos requisitos de roteamento
  1. Roteamento complexo
  • Exchanges de tópico com wildcards
  • Roteamento baseado em header
  • Dead-letter queues
  1. Padrões de mensagens mistos
  • Necessidade de filas e pub/sub
  • Diferentes garantias de entrega por fila

Exemplo de implementação RabbitMQ:

typescript// Implementação de publicador RabbitMQ
import { connect, Channel, Connection } from 'amqplib';

class RabbitMQPublisher {
  private connection: Connection | null = null;
  private channel: Channel | null = null;

  constructor(private uri: string) {}

  async connect(): Promise<void> {
    this.connection = await connect(this.uri);
    this.channel = await this.connection.createChannel();

    // Declarar exchange
    await this.channel.assertExchange('events', 'topic', { durable: true });

    console.log('Publicador RabbitMQ conectado');
  }

  async publish(routingKey: string, message: any): Promise<void> {
    if (!this.channel) {
      throw new Error('Canal RabbitMQ não inicializado');
    }

    try {
      const published = this.channel.publish(
        'events',
        routingKey,
        Buffer.from(JSON.stringify(message)),
        {
          persistent: true,
          contentType: 'application/json',
          timestamp: new Date().getTime().toString()
        }
      );

      if (!published) {
        console.warn('Mensagem não pôde ser publicada');
      }
    } catch (error) {
      console.error('Falha ao publicar mensagem:', error);
      throw error;
    }
  }

  async disconnect(): Promise<void> {
    if (this.connection) {
      await this.connection.close();
    }
  }
}

// Implementação de consumidor RabbitMQ
class RabbitMQConsumer {
  private connection: Connection | null = null;
  private channel: Channel | null = null;

  constructor(
    private uri: string,
    private queueName: string,
    private routingKey: string,
    private messageHandler: MessageHandler
  ) {}

  async start(): Promise<void> {
    this.connection = await connect(this.uri);
    this.channel = await this.connection.createChannel();

    // Declarar exchange e fila
    await this.channel.assertExchange('events', 'topic', { durable: true });
    await this.channel.assertQueue(this.queueName, {
      durable: true,
      arguments: {
        'x-dead-letter-exchange': 'dlx',
        'x-dead-letter-routing-key': this.queueName
      }
    });

    // Bind fila ao exchange
    await this.channel.bindQueue(this.queueName, 'events', this.routingKey);

    // Definir prefetch
    await this.channel.prefetch(10);

    // Consumir mensagens
    await this.channel.consume(this.queueName, async (msg) => {
      if (!msg) return;

      try {
        const message = JSON.parse(msg.content.toString());
        console.log(`Processando mensagem:`, message);

        await this.messageHandler(message);

        this.channel.ack(msg);
      } catch (error) {
        console.error('Falha ao processar mensagem:', error);

        // Rejeitar e enfileirar novamente (máximo 3 vezes)
        if (msg.fields.redelivered && msg.fields.deliveryTag > 3) {
          this.channel.reject(msg, false); // Dead-letter
        } else {
          this.channel.reject(msg, true); // Requeue
        }
      }
    });

    console.log('Consumidor RabbitMQ iniciado');
  }

  async stop(): Promise<void> {
    if (this.connection) {
      await this.connection.close();
    }
  }
}

Considerações operacionais RabbitMQ:

yaml# Configuração RabbitMQ para produção
rabbitmq:
  default_pass: ${RABBITMQ_PASSWORD}
  default_user: admin
  vm_memory_high_watermark: 0.4
  disk_free_limit: 1000000000  # 1GB
  heartbeat: 60
  channel_max: 2048
  default_vhost: /

plugins:
  - rabbitmq_management
  - rabbitmq_prometheus
  - rabbitmq_shovel
  - rabbitmq_federation

Trade-offs do RabbitMQ:

Prós:

  • Capacidades de roteamento flexíveis
  • Múltiplos protocolos de mensagens
  • Bom desempenho para a maioria dos workloads
  • Ecossistema maduro e ferramentas
  • Suporte para dead-letter queues

Contras:

  • Escalabilidade horizontal limitada
  • Requer clustering para alta disponibilidade
  • Não ideal para streaming de eventos de alto volume
  • Configuração complexa para clustering
  • Intensivo em memória

Redis Streams: Leve e rápido

Arquitetura e pontos fortes

Redis Streams é uma estrutura de dados de log adicionada ao Redis, fornecendo capacidades básicas de streaming com o desempenho e simplicidade do Redis.

Quando Redis Streams é a escolha certa:

  1. Workloads simples
  • Volume de mensagem baixo a moderado
  • Padrões simples de pub/sub
  • Já usando Redis para caching
  1. Crítico para performance
  • Latência sub-milissegundo necessária
  • Processamento de mensagem simples
  • Armazenamento de dados temporário aceitável
  1. Prototipagem rápida
  • Ciclo de desenvolvimento rápido
  • Overhead operacional mínimo
  • Não precisa de recursos complexos

Exemplo de implementação Redis Streams:

typescript// Implementação de produtor Redis Streams
import { createClient } from 'redis';

class RedisStreamsProducer {
  private client: ReturnType<typeof createClient>;
  private streamName: string;

  constructor(url: string, streamName: string) {
    this.client = createClient({ url });
    this.streamName = streamName;
  }

  async connect(): Promise<void> {
    await this.client.connect();
    console.log('Produtor Redis Streams conectado');
  }

  async sendEvent(field: string, value: any): Promise<void> {
    try {
      const result = await this.client.xAdd(
        this.streamName,
        '*',
        {
          [field]: JSON.stringify(value),
          timestamp: Date.now().toString()
        }
      );

      console.log(`Evento enviado para ${this.streamName}:`, result);
    } catch (error) {
      console.error('Falha ao enviar evento:', error);
      throw error;
    }
  }

  async disconnect(): Promise<void> {
    await this.client.disconnect();
  }
}

// Implementação de consumidor Redis Streams
class RedisStreamsConsumer {
  private client: ReturnType<typeof createClient>;
  private streamName: string;
  private consumerGroup: string;
  private consumerName: string;

  constructor(
    url: string,
    streamName: string,
    consumerGroup: string,
    consumerName: string,
    private messageHandler: MessageHandler
  ) {
    this.client = createClient({ url });
    this.streamName = streamName;
    this.consumerGroup = consumerGroup;
    this.consumerName = consumerName;
  }

  async start(): Promise<void> {
    await this.client.connect();

    // Criar grupo de consumidor se não existir
    try {
      await this.client.xGroupCreate(this.streamName, this.consumerGroup, '0', {
        MKSTREAM: true
      });
      console.log(`Grupo de consumidor criado: ${this.consumerGroup}`);
    } catch (error) {
      // Grupo já existe, ignorar
    }

    console.log('Consumidor Redis Streams iniciado');

    // Iniciar consumo
    while (true) {
      try {
        const messages = await this.client.xReadGroup(
          this.consumerGroup,
          this.consumerName,
          [
            {
              key: this.streamName,
              id: '>'
            }
          ],
          {
            COUNT: 10,
            BLOCK: 5000  // Bloquear por 5 segundos
          }
        );

        if (messages) {
          for (const stream of messages) {
            for (const message of stream.messages) {
              try {
                const field = Object.keys(message.message)[0];
                const value = JSON.parse(message.message[field] as string);

                console.log(`Processando mensagem:`, message.id);

                await this.messageHandler(value);

                // Reconhecer mensagem
                await this.client.xAck(this.streamName, this.consumerGroup, message.id);
              } catch (error) {
                console.error('Falha ao processar mensagem:', error);
                // Mensagem será reprocessada pelo grupo de consumidor
              }
            }
          }
        }
      } catch (error) {
        console.error('Erro ao consumir mensagens:', error);
        await this.sleep(1000); // Esperar antes de tentar novamente
      }
    }
  }

  private sleep(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  async stop(): Promise<void> {
    await this.client.disconnect();
  }
}

Trade-offs do Redis Streams:

Prós:

  • Extremamente rápido (latência sub-milissegundo)
  • Simples de implementar e operar
  • Requisitos mínimos de recursos
  • Grupos de consumidor para processamento paralelo
  • Funciona com infraestrutura Redis existente

Contras:

  • Persistência limitada (baseada em memória, AOF opcional)
  • Sem capacidades avançadas de roteamento
  • Ferramentas limitadas comparadas a Kafka/RabbitMQ
  • Não adequado para retenção de longo prazo
  • Escalabilidade limitada (instância única)

Amazon SQS: Gerenciado e simples

Arquitetura e pontos fortes

Amazon SQS é um serviço de fila de mensagens totalmente gerenciado que elimina overhead operacional. Fornece throughput ilimitado e escalamento automático.

Quando Amazon SQS é a escolha certa:

  1. Implantações nativas AWS
  • Já usando infraestrutura AWS
  • Quer overhead operacional mínimo
  • Necessita escalamento automático
  1. Requisitos simples de fila
  • Filas FIFO ou padrão básicas
  • Não precisa de roteamento avançado
  • Aceita lock-in de nuvem
  1. Complexidade operacional baixa
  • Não quer gerenciar brokers de mensagens
  • Necessita alta disponibilidade pronta
  • Quer previsibilidade de preços

Exemplo de implementação Amazon SQS:

typescript// Implementação de produtor SQS
import { SQSClient, SendMessageCommand } from '@aws-sdk/client-sqs';

class SQSProducer {
  private client: SQSClient;
  private queueUrl: string;

  constructor(
    region: string,
    queueUrl: string,
    credentials?: {
      accessKeyId: string;
      secretAccessKey: string;
    }
  ) {
    this.client = new SQSClient({
      region,
      credentials
    });
    this.queueUrl = queueUrl;
  }

  async sendMessage(message: any): Promise<void> {
    try {
      const command = new SendMessageCommand({
        QueueUrl: this.queueUrl,
        MessageBody: JSON.stringify(message),
        MessageAttributes: {
          Timestamp: {
            DataType: 'Number',
            StringValue: Date.now().toString()
          },
          ContentType: {
            DataType: 'String',
            StringValue: 'application/json'
          }
        }
      });

      const response = await this.client.send(command);

      console.log(`Mensagem enviada para SQS:`, response.MessageId);
    } catch (error) {
      console.error('Falha ao enviar mensagem:', error);
      throw error;
    }
  }
}

// Implementação de consumidor SQS
import { ReceiveMessageCommand, DeleteMessageCommand } from '@aws-sdk/client-sqs';

class SQSConsumer {
  private client: SQSClient;
  private queueUrl: string;
  private maxNumberOfMessages: number;
  private waitTimeSeconds: number;

  constructor(
    region: string,
    queueUrl: string,
    private messageHandler: MessageHandler,
    credentials?: {
      accessKeyId: string;
      secretAccessKey: string;
    }
  ) {
    this.client = new SQSClient({
      region,
      credentials
    });
    this.queueUrl = queueUrl;
    this.maxNumberOfMessages = 10;
    this.waitTimeSeconds = 20;  // Long polling
  }

  async start(): Promise<void> {
    console.log('Consumidor SQS iniciado');

    while (true) {
      try {
        const command = new ReceiveMessageCommand({
          QueueUrl: this.queueUrl,
          MaxNumberOfMessages: this.maxNumberOfMessages,
          WaitTimeSeconds: this.waitTimeSeconds,
          AttributeNames: ['All'],
          MessageAttributeNames: ['All']
        });

        const response = await this.client.send(command);

        if (response.Messages && response.Messages.length > 0) {
          console.log(`Recebidas ${response.Messages.length} mensagens`);

          for (const message of response.Messages) {
            try {
              const body = JSON.parse(message.Body || '{}');

              console.log(`Processando mensagem:`, message.MessageId);

              await this.messageHandler(body);

              // Deletar mensagem após processamento bem-sucedido
              const deleteCommand = new DeleteMessageCommand({
                QueueUrl: this.queueUrl,
                ReceiptHandle: message.ReceiptHandle
              });

              await this.client.send(deleteCommand);
            } catch (error) {
              console.error('Falha ao processar mensagem:', error);
              // Mensagem será reprocessada por timeout de visibilidade SQS
            }
          }
        }
      } catch (error) {
        console.error('Erro ao consumir mensagens:', error);
        await this.sleep(5000);  // Esperar antes de tentar novamente
      }
    }
  }

  private sleep(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}

Trade-offs do Amazon SQS:

Prós:

  • Totalmente gerenciado (sem overhead operacional)
  • Throughput ilimitado e escalamento automático
  • Monitoramento e métricas integradas
  • Alta disponibilidade pronta
  • Modelo de preços simples

Contras:

  • Lock-in de nuvem (AWS)
  • Sem capacidades avançadas de roteamento
  • Tamanho de mensagem limitado (256KB)
  • Não adequado para casos de uso complexos
  • Latência mais alta comparada a Redis/RabbitMQ

Framework de decisão

Perguntas para guiar sua seleção

1. Qual é seu volume de mensagens?

  • < 1K mensagens/seg → Redis Streams ou RabbitMQ
  • 1K-10K mensagens/seg → RabbitMQ ou SQS
  • > 10K mensagens/seg → Kafka

2. Você precisa fazer replay de mensagens?

  • Sim → Kafka ou Redis Streams
  • Não → RabbitMQ ou SQS

3. Quais garantias de ordenação você precisa?

  • Ordenação estrita → RabbitMQ ou Kafka (por partição)
  • Melhor esforço → SQS ou Redis Streams

4. Qual é sua capacidade operacional?

  • Quer ops mínimas → SQS ou Redis Streams
  • Pode gerenciar infraestrutura → RabbitMQ ou Kafka

5. Qual é sua estratégia de nuvem?

  • Multi-cloud → Kafka ou RabbitMQ
  • Nativo AWS → SQS
  • Cloud-agnostic → Kafka ou RabbitMQ

6. Qual é seu requisito de retenção?

  • Longo prazo (semanas/meses) → Kafka
  • Médio prazo (dias) → RabbitMQ ou SQS
  • Curto prazo (horas) → Redis Streams

Abordagens híbridas

Em sistemas complexos, você pode precisar de múltiplos brokers de mensagens para diferentes casos de uso:

typescript// Arquitetura híbrida de broker de mensagens
class HybridMessageBroker {
  private kafkaProducer: KafkaEventProducer;
  private rabbitmqPublisher: RabbitMQPublisher;
  private redisStreamsProducer: RedisStreamsProducer;

  constructor() {
    this.kafkaProducer = new KafkaEventProducer(
      ['kafka-broker:9092'],
      'my-app',
      'high-volume-events'
    );

    this.rabbitmqPublisher = new RabbitMQPublisher(
      'amqp://rabbitmq:5672'
    );

    this.redisStreamsProducer = new RedisStreamsProducer(
      'redis://redis:6379',
      'fast-events'
    );
  }

  async sendEvent(event: any): Promise<void> {
    switch (event.type) {
      case 'high_volume_analytics':
        // Usar Kafka para eventos de alto volume
        await this.kafkaProducer.sendEvent(event.id, event);
        break;

      case 'business_event':
        // Usar RabbitMQ para eventos de negócio com roteamento complexo
        await this.rabbitmqPublisher.publish(event.routingKey, event);
        break;

      case 'low_latency':
        // Usar Redis Streams para eventos de baixa latência
        await this.redisStreamsProducer.sendEvent('event', event);
        break;

      default:
        throw new Error(`Tipo de evento desconhecido: ${event.type}`);
    }
  }
}

Conclusão

O broker de mensagens certo depende de seus requisitos específicos, não do que é "popular" ou do que concorrentes estão usando.

  • Kafka para streaming de eventos de alto volume e requisitos de replay
  • RabbitMQ para mensagens de propósito geral com roteamento complexo
  • Redis Streams para workloads simples e de baixa latência
  • Amazon SQS para implantações nativas AWS com ops mínimas

Comece com a solução mais simples que atende seus requisitos. Você sempre pode migrar para um broker mais complexo se necessário—mas o custo de complexidade prematura é alto.


Precisa de ajuda projetando uma arquitetura de microserviços assíncronos? Fale com a Imperialis sobre seleção de broker de mensagens, design de arquitetura e implementação para seu sistema de produção.

Fontes

Leituras relacionadas