SYSTEM DESIGN · MENSAGERIA · LEITURA DE ~13 MIN

Filas e Mensageria

Toda fila de back pressure precisa de um motor por baixo. Redis, RabbitMQ, Kafka, Celery e BullMQ resolvem o mesmo problema de fundo — segurar trabalho e desacoplar sistemas —, mas cada um do seu jeito.

Diagrama mostrando o fluxo usuario, API, fila, worker e banco de dados, com RabbitMQ, Redis, BullMQ e Celery citados como pecas por tras da fila.
FILA + WORKER + BACK PRESSURE · AS PEÇAS POR TRÁS DO FLUXO ASSÍNCRONO

SEÇÃO 01

Por que existe fila e worker

No artigo sobre back pressure, a fila aparece como uma peça abstrata: um espaço limitado entre a API e os workers, que impede que a entrada destrua um componente mais lento na saída. Mas "fila" não é uma coisa só. Na prática, ela é implementada por ferramentas diferentes, e cada uma resolve uma parte diferente do problema.

PAPÉISGENÉRICO
Producer
   ↓
Broker / Fila
   ↓
Consumer / Worker

Redis guarda estrutura de dados rápida em memória. RabbitMQ roteia mensagens com garantia de entrega. Kafka mantém um log de eventos que vários consumidores podem ler de forma independente. Celery e BullMQ são bibliotecas que rodam tasks em background usando um desses brokers por baixo.

Este artigo passa por cada uma dessas peças e termina mostrando onde exatamente o back pressure entra quando elas trabalham juntas.

SEÇÃO 02

Redis: a peça multiuso

Redis é uma estrutura de dados em memória. A forma mais simples de pensar nele: um dicionário gigante, muito rápido, que também sabe guardar listas, sets, hashes e streams — não só pares chave-valor.

Cartaz ilustrado do Redis explicando que e uma estrutura de dados em memoria usada como cache, fila e pub/sub, com casos de uso como cache-aside, sessoes, rate limiting e distributed locks.
REDIS · IN-MEMORY DATA STORE

Por causa dessa versatilidade, Redis vira base para várias coisas diferentes: cache (ver estratégias de cache), sessões de usuário, rate limiting, locks distribuídos e, com uma lista ou um Stream, uma fila simples.

FILA SIMPLESREDIS
LPUSH fila:emails "{ \"to\": \"a@x.com\" }"

BRPOP fila:emails 0
REDIS SOZINHO NÃO É UM BROKER COMPLETO

Uma lista Redis não tem ACK, retry automático nem dead-letter queue: se o worker cair depois do BRPOP e antes de terminar o processamento, a mensagem some. É por isso que ferramentas como BullMQ existem — elas usam Redis como armazenamento, mas adicionam a camada de garantias em cima.

SEÇÃO 03

RabbitMQ: broker de mensagens

RabbitMQ é um message broker dedicado: um servidor cuja única função é receber, rotear e entregar mensagens entre quem produz e quem consome, com confirmação de entrega.

Cartaz ilustrado do RabbitMQ mostrando o fluxo producer, exchange, queue e consumer, com casos de uso como jobs assincronos, notificacoes e dead-letter queue.
RABBITMQ · MESSAGE BROKER
FLUXORABBITMQ
Producer
   ↓
Exchange (roteia por regra)
   ↓
Queue
   ↓
Consumer → ACK

A peça extra em relação a uma fila Redis é o ACK explícito: o consumer só confirma a mensagem depois de terminar de processá-la. Se o consumer cair no meio, o RabbitMQ redelivera a mensagem para outro worker — nada se perde por causa de um crash isolado.

APROFUNDANDO: EXCHANGE

O exchange é quem decide para qual fila cada mensagem vai. Um exchange direct roteia por uma chave exata; um topic roteia por padrão (pedido.*); um fanout copia a mensagem para todas as filas ligadas a ele. Mensagens que falham repetidamente podem cair numa dead-letter queue em vez de tentar para sempre.

SEÇÃO 04

Kafka: streaming de eventos

Kafka resolve um problema diferente do RabbitMQ. Em vez de uma fila que esvazia conforme é consumida, Kafka mantém um log de eventos: cada mensagem publicada em um tópico fica retida por um tempo configurável, e qualquer consumer pode lê-la — inclusive mais de uma vez.

Cartaz ilustrado do Kafka mostrando producer publicando em um topico com particoes, lido por multiplos consumers, com casos de uso como eventos de dominio, analytics e replay.
KAFKA · EVENT STREAMING
FLUXOKAFKA
Producer
   ↓
Topic (partições)
   ↓
Consumer A · Consumer B · Consumer C
   (cada um lê independente)

Isso muda o que é possível fazer: um evento payment.completed pode ser lido ao mesmo tempo por um serviço de analytics, um serviço de auditoria e um serviço de recomendação, sem que um dependa do outro nem "roube" a mensagem dos demais.

FILA X LOG

No RabbitMQ, a mensagem some da fila depois do ACK. No Kafka, o evento continua no log até o tempo de retenção expirar — o que permite replay: reprocessar os últimos N eventos, ou ligar um consumer novo que lê tudo desde o início.

SEÇÃO 05

Celery: task queue em Python

Celery é um framework Python para rodar tasks em background usando workers. Ele não é um broker — ele precisa de um (normalmente Redis ou RabbitMQ) para guardar as tasks pendentes.

Cartaz ilustrado do Celery mostrando o fluxo app Python, broker Redis ou RabbitMQ e Celery worker, com casos de uso como e-mails, ETL e tarefas periodicas.
CELERY · DISTRIBUTED TASK QUEUE
EXEMPLOPYTHON
@app.task(bind=True, max_retries=3)
def send_email(self, user_id):
    try:
        email_service.send(user_id)
    except Exception as exc:
        raise self.retry(exc=exc, countdown=10)

# na API:
send_email.delay(user_id)

A chamada .delay(...) publica a task no broker e retorna imediatamente. Um worker Celery, rodando separado da API, pega a task e executa. Retries, agendamento periódico (Celery beat) e jobs longos fazem parte do que o framework já resolve pronto.

SEÇÃO 06

BullMQ: task queue em Node.js

BullMQ cumpre o mesmo papel do Celery, mas para o ecossistema Node/TypeScript, e é construído diretamente sobre Redis.

Cartaz ilustrado do BullMQ mostrando o fluxo API Node, Redis, queue e worker, com casos de uso como notificacoes, geracao de times e processamento assincrono.
BULLMQ · NODE.JS JOB QUEUE
EXEMPLOTYPESCRIPT
const queue = new Queue("notifications", { connection: redis });
await queue.add("push", { userId }, { attempts: 3 });

new Worker("notifications", async (job) => {
  await pushService.send(job.data.userId);
}, { connection: redis, concurrency: 20 });

O concurrency ali não é detalhe: é exatamente o tipo de limite discutido em back pressure — quantos jobs esse worker processa ao mesmo tempo. Se 5000 notificações entrarem de uma vez, a fila cresce, mas o worker continua consumindo no ritmo que ele suporta, em vez de tentar tudo junto.

SEÇÃO 07

Task x evento: comando ou fato?

Com as cinco ferramentas na mesa, fica mais fácil ver uma distinção que confunde bastante gente: task e evento não são sinônimos.

Comparacao entre task, uma instrucao de trabalho como send_email, e evento, um fato ocorrido como payment.completed, com a regra pratica de usar fila de jobs para tasks e stream para eventos.
TASK X EVENTO · COMMAND X EVENT

Uma task é uma instrução de trabalho — "faça isso": send_email, generate_teams, resize_image. Normalmente um único worker executa e o resultado importa para quem pediu. Um evento é um fato que já aconteceu — "isso aconteceu": payment.completed, match.cancelled. Vários consumidores podem reagir a ele de forma independente, e nenhum "dono" precisa saber quem está ouvindo.

REGRA PRÁTICA

Task → fila de jobs (BullMQ, Celery, RabbitMQ). Evento → stream / event bus (Kafka). Misturar os dois é comum no começo: usar Kafka para mandar "gere esse PDF" ou usar uma fila de jobs para avisar dez serviços diferentes que um pagamento foi confirmado. Os dois funcionam torto quando usados no papel do outro.

SEÇÃO 08

Tudo junto: um mini e-commerce

Colocando as peças lado a lado num sistema só, fica mais claro onde cada uma entra.

Diagrama de um e-commerce mostrando API em Node consultando PostgreSQL e Redis de forma sincrona, publicando jobs em BullMQ e Redis para workers de notificacao, faturamento e PDF, e eventos no Kafka para consumers de analytics, auditoria e recomendacoes.
MINI DS · E-COMMERCE · COMO TUDO SE ENCAIXA

Criar um pedido é síncrono: a API consulta o PostgreSQL, confirma o estoque e responde — o mesmo caminho de consistência descrito em back pressure. Notificar o cliente, gerar a fatura em PDF e atualizar o cache são async: viram jobs numa fila BullMQ/Redis, processados por workers dedicados. Analytics, auditoria e recomendações não pedem uma resposta imediata a ninguém: são consumers independentes de um evento no Kafka.

FerramentaTipoQuando usar
RedisCache / estrutura rápidaLeituras rápidas, sessões, rate limiting, locks
RabbitMQMessage brokerDesacoplar serviços com garantia de entrega e ACK
KafkaEvent streamingMúltiplos consumidores, alto throughput, replay
CeleryTask queue (Python)Jobs em background no ecossistema Python
BullMQTask queue (Node)Jobs em background no ecossistema Node/TS

SEÇÃO 09

Ideia central

Nenhuma dessas ferramentas substitui a disciplina de back pressure — elas só dão o material com que ela é construída.

CAMADASCOM AS PEÇAS
Internet
   ↓
Rate Limit
   ↓
Concurrency Limit
   ↓
Connection Pool
   ↓
Bounded Queue (RabbitMQ / BullMQ / Celery)
   ↓
Workers
   ↓
PostgreSQL · Kafka (eventos) · Redis (cache)

Trocar Redis por RabbitMQ, ou RabbitMQ por Kafka, não elimina a pergunta feita em back pressure: o que acontece quando entra mais trabalho do que o sistema consegue escoar? Cada ferramenta muda a resposta técnica — tamanho de fila, ACK, retenção, replay —, mas a decisão de arquitetura continua sendo a mesma: aceitar até onde dá para operar bem, e deixar claro o que acontece com o excesso.

FIM · OBRIGADO POR LER

A fila é só a interface. O que importa é o contrato por trás dela.

Redis, RabbitMQ, Kafka, Celery e BullMQ resolvem partes diferentes do mesmo problema: como aceitar trabalho sem derrubar quem vem depois.

LER BACK PRESSURE VOLTAR AOS CONTEÚDOS