---
title: "Mensageria em Go: RabbitMQ, Kafka, NATS ou SQS?"
url: "https://golang.com.br/blog/mensageria-go-rabbitmq-kafka-nats-sqs/"
markdown_url: "https://golang.com.br/blog/mensageria-go-rabbitmq-kafka-nats-sqs.MD"
description: "Aprenda quando usar RabbitMQ, Kafka, NATS, SQS ou Redis Streams em projetos Go: filas, eventos, streaming, retries, dead-letter queue e exemplos práticos."
date: "2026-05-20"
author: "Golang Brasil"
---

# Mensageria em Go: RabbitMQ, Kafka, NATS ou SQS?

Aprenda quando usar RabbitMQ, Kafka, NATS, SQS ou Redis Streams em projetos Go: filas, eventos, streaming, retries, dead-letter queue e exemplos práticos.


Mensageria em Go aparece quando uma API deixa de fazer tudo dentro da requisição HTTP e passa a delegar trabalho para outro processo. Enviar e-mail, processar pagamento, gerar relatório, sincronizar dados, consumir webhooks, recalcular score, publicar eventos de auditoria e alimentar pipelines são exemplos clássicos. O código Go continua simples, mas a arquitetura muda: em vez de chamar tudo em linha, você coloca uma mensagem em uma fila ou tópico e deixa consumidores processarem no ritmo certo.

O problema é que "mensageria" virou uma palavra grande demais. RabbitMQ, Kafka, NATS, SQS, Redis Streams, Google Pub/Sub e outros sistemas resolvem problemas parecidos, mas não iguais. Escolher errado pode transformar uma solução simples em uma operação pesada, ou pior: esconder perda de mensagens, retries infinitos e duplicidade de processamento.

Este guia explica como pensar em mensageria em projetos Go, quando usar cada tecnologia e quais padrões importam em produção. Se você ainda está no começo da jornada, leia antes o guia de [concorrência em Go](/aprenda/concorrencia-go/) e o artigo sobre [worker pool em Go](/blog/worker-pool-go-fila-jobs/). Worker pool resolve paralelismo dentro do processo; mensageria resolve trabalho assíncrono entre processos, deploys e serviços diferentes.

## Quando uma fila faz sentido

Você não precisa de broker para tudo. Uma chamada HTTP síncrona é mais simples quando o usuário precisa da resposta imediatamente, o volume é baixo e a falha deve aparecer na hora. Uma fila começa a fazer sentido quando pelo menos uma destas condições aparece:

- O trabalho demora mais do que a requisição deveria esperar.
- O produtor e o consumidor precisam escalar separadamente.
- Uma falha temporária deve ser retentada sem perder o evento.
- Você quer suavizar picos de tráfego.
- Mais de um sistema precisa reagir ao mesmo acontecimento.
- O processamento pode ser eventual, não instantâneo.

Em Go, o produtor normalmente publica uma struct serializada como JSON, Protobuf ou Avro. O consumidor lê a mensagem, valida o schema, executa o trabalho e confirma o processamento. O detalhe importante: quase todo broker moderno trabalha com entrega "ao menos uma vez". Isso significa que a mesma mensagem pode chegar mais de uma vez. Seu handler precisa ser idempotente.

## RabbitMQ: filas de trabalho previsíveis

RabbitMQ é uma boa escolha para filas clássicas de trabalho: jobs discretos, consumidores concorrentes, confirmação explícita, retry, dead-letter queue e roteamento flexível. Ele combina bem com APIs Go que precisam tirar trabalho pesado do caminho da requisição.

Use RabbitMQ quando você quer dizer: "cada mensagem deve ser processada por um consumidor, com controle de ack, prefetch e retry". Exemplos: envio de e-mails, processamento de imagens, importação de planilhas, webhooks recebidos de parceiros e tarefas administrativas.

O padrão em Go costuma ter estes elementos:

- Um producer que publica mensagens com `delivery_mode` persistente.
- Um consumer com `prefetch` limitado para controlar concorrência.
- `ack` apenas depois do trabalho terminar.
- `nack` ou rejeição controlada quando o erro é retryable.
- Dead-letter queue para mensagens que falharam muitas vezes.

O erro comum é tratar RabbitMQ como banco de dados ou log eterno. Ele não foi feito para guardar histórico por meses nem para reprocessar todos os eventos desde o começo. Para isso, Kafka costuma ser melhor.

## Kafka: eventos, streaming e retenção

Kafka é mais adequado quando a mensagem representa um evento de negócio e pode ser consumida por múltiplos grupos independentes. Em vez de pensar em "fila de jobs", pense em "log de eventos". Um pedido criado, um pagamento aprovado, uma nota fiscal emitida ou uma alteração de perfil podem ser publicados em tópicos e consumidos por antifraude, analytics, notificações e data platform.

Use Kafka quando você precisa de retenção, replay, alto volume, particionamento e múltiplos consumidores com ritmos diferentes. Ele é comum em fintechs, marketplaces, empresas de dados e plataformas com vários times consumindo eventos.

Em Go, bibliotecas como `segmentio/kafka-go`, `confluent-kafka-go` e Sarama aparecem bastante. A decisão entre elas depende do ambiente, mas o desenho arquitetural pesa mais do que a biblioteca:

- Defina chave de partição com cuidado para preservar ordem por entidade.
- Versione eventos, porque consumidores antigos continuam existindo.
- Monitore consumer lag.
- Planeje reprocessamento antes de precisar dele.
- Evite publicar eventos gigantes; guarde payload grande em storage e publique referência.

Kafka traz mais poder, mas também mais operação. Para uma aplicação pequena que só precisa de fila de e-mail, ele provavelmente é excesso.

## NATS: simplicidade, baixa latência e JetStream

NATS é atraente para times Go porque é simples, rápido e tem uma experiência de desenvolvimento leve. O modelo básico de publish/subscribe funciona bem para comunicação interna de serviços, notificações e comandos efêmeros. Com JetStream, NATS ganha persistência, consumer groups, replay e padrões mais próximos de fila/event streaming.

Use NATS quando você valoriza baixa latência, operação enxuta e comunicação simples entre serviços. Ele também é uma boa opção quando RabbitMQ parece pesado demais e Kafka parece grande demais para o problema.

O cuidado é separar NATS core de NATS JetStream. NATS core é excelente para mensagens efêmeras; se o consumidor cair, a mensagem pode não estar lá depois. JetStream é a escolha quando você precisa persistir, confirmar e reprocessar. Em produção, seja explícito sobre qual semântica seu sistema exige.

## SQS: fila gerenciada na AWS

Amazon SQS é uma fila gerenciada. Você não opera broker, não gerencia cluster e não se preocupa com disco. Para times que já estão na AWS, isso reduz bastante a carga operacional.

Use SQS quando você quer fila simples, escalável e confiável sem administrar infraestrutura. Ela funciona muito bem com workers Go rodando em ECS, EKS, Lambda ou instâncias comuns. Visibility timeout, dead-letter queue e long polling cobrem a maioria dos casos de background jobs.

O ponto de atenção é o modelo de entrega. SQS também pode entregar mensagens duplicadas. A ordem só é garantida em filas FIFO, com limitações próprias. Para streaming, replay e múltiplos grupos consumidores, Kafka ou Kinesis podem fazer mais sentido.

## Redis Streams: útil, mas cuidado com durabilidade

Redis Streams pode ser uma boa solução quando Redis já faz parte da stack e o volume é moderado. Ele oferece append-only stream, consumer groups e acknowledge. Para filas internas, protótipos e sistemas menores, pode ser prático.

Mas Redis continua sendo Redis: a estratégia de persistência, memória, eviction policy e backup importam. Não escolha Redis Streams apenas porque "já temos Redis" se a perda de mensagens for inaceitável. Em cenários críticos, um broker dedicado ou serviço gerenciado costuma ser uma decisão mais segura.

## Comparativo rápido

| Caso de uso | Melhor primeira escolha |
|---|---|
| Jobs assíncronos clássicos | RabbitMQ ou SQS |
| Eventos para vários times | Kafka |
| Comunicação leve entre serviços | NATS |
| Fila gerenciada na AWS | SQS |
| Replay e retenção longa | Kafka |
| Baixa latência com operação simples | NATS |
| Stack pequena que já usa Redis | Redis Streams |

A regra prática: se você fala "processar tarefas", comece pensando em RabbitMQ ou SQS. Se você fala "publicar fatos do negócio para vários consumidores", comece pensando em Kafka. Se você fala "mensagens rápidas entre serviços", avalie NATS.

## Exemplo de consumidor idempotente em Go

Independentemente do broker, o consumidor precisa tolerar duplicidade. Um jeito comum é gravar uma chave única do evento antes de executar efeitos externos:

```go
type EventoPagamento struct {
    ID        string `json:"id"`
    PedidoID  string `json:"pedido_id"`
    Valor     int64  `json:"valor_centavos"`
}

func ProcessarPagamento(ctx context.Context, db *sql.DB, evento EventoPagamento) error {
    tx, err := db.BeginTx(ctx, nil)
    if err != nil {
        return err
    }
    defer tx.Rollback()

    var jaProcessado bool
    err = tx.QueryRowContext(ctx, `
        SELECT EXISTS(SELECT 1 FROM eventos_processados WHERE id = $1)
    `, evento.ID).Scan(&jaProcessado)
    if err != nil {
        return err
    }
    if jaProcessado {
        return tx.Commit()
    }

    if err := aplicarRegraDeNegocio(ctx, tx, evento); err != nil {
        return err
    }

    _, err = tx.ExecContext(ctx, `
        INSERT INTO eventos_processados (id, processado_em) VALUES ($1, NOW())
    `, evento.ID)
    if err != nil {
        return err
    }

    return tx.Commit()
}
```

Esse padrão não depende de RabbitMQ, Kafka ou SQS. Ele depende de reconhecer uma verdade operacional: mensagens podem repetir, consumidores podem cair depois de executar metade do trabalho e brokers podem reenviar. Go facilita escrever handlers pequenos, mas a segurança vem do desenho.

## Retries, DLQ e observabilidade

Um sistema de mensageria sem observabilidade vira uma caixa-preta. No mínimo, monitore:

- Tamanho da fila ou lag do consumidor.
- Idade da mensagem mais antiga.
- Taxa de processamento por segundo.
- Taxa de erro por tipo.
- Número de mensagens em dead-letter queue.
- Tempo médio e p95 de processamento.

Retries também precisam de limite. Retentar para sempre uma mensagem inválida só consome recurso. Separe erro temporário de erro permanente. Timeout de API externa, indisponibilidade de banco e limite de taxa costumam ser temporários. Payload inválido, ID inexistente e contrato quebrado costumam ir para DLQ depois de poucas tentativas.

Combine mensageria com [slog em Go](/blog/slog-go-logging-estruturado/) para logs estruturados, [migrations em Go](/blog/migrations-go-banco-dados-producao/) para tabelas de idempotência e [testes em Go](/aprenda/testes-go/) para validar handlers sem depender de broker real em todo teste.

## Como estudar mensageria para vagas Go

Muitas [vagas Go no Brasil](/vagas/) citam Kafka, RabbitMQ, SQS, Kubernetes, Docker, PostgreSQL e observabilidade. Em entrevista, o diferencial não é decorar a API de uma biblioteca. É explicar trade-offs: por que escolher uma fila, como lidar com duplicidade, como fazer retry sem derrubar o sistema e como saber se consumidores estão atrasados.

Um bom projeto de portfólio é uma API Go que recebe pedidos, grava no PostgreSQL, publica um evento e processa notificações em um worker separado. Depois adicione DLQ, logs com correlação, métricas e um teste de idempotência. Esse projeto demonstra backend real melhor do que mais um CRUD isolado.

Se você ainda está procurando a primeira oportunidade ou comparando stacks, acompanhe também o portal <a href="https://eu.dev.br/vagas/" target="_blank" rel="noopener noreferrer" onclick="umami.track('portfolio-site-click', { destination: 'eu.dev.br' })">eu.dev.br</a>, que reúne vagas brasileiras de tecnologia por senioridade e ajuda a enxergar quais ferramentas aparecem fora do nicho Go.

## Conclusão

Mensageria em Go não é sobre escolher a tecnologia mais famosa. É sobre entender a semântica que seu produto precisa. RabbitMQ e SQS resolvem muito bem filas de trabalho. Kafka brilha em eventos duráveis, replay e múltiplos consumidores. NATS entrega simplicidade e baixa latência, especialmente com JetStream quando há necessidade de persistência. Redis Streams pode ser útil em stacks menores, desde que os riscos de durabilidade estejam claros.

Comece pelo problema: job, evento, stream ou comunicação efêmera. Depois escolha o broker. Por fim, escreva consumidores idempotentes, limite retries, acompanhe DLQ e monitore lag. Essa disciplina vale mais do que qualquer biblioteca específica e é exatamente o tipo de maturidade que diferencia código Go de estudo de código Go pronto para produção.
