Quando Você Deve Usar o Redis como um Message Broker?
Descubra os cenários ideais para aproveitar o Redis como um message broker usando seus dois principais recursos: Pub/Sub e Streams. Este guia abrangente detalha as vantagens de desempenho, baixa latência e benefícios de infraestrutura da mensageria Redis. Aprenda as diferenças cruciais entre Pub/Sub efêmero e Streams duráveis, entenda suas limitações em comparação com brokers dedicados como o Kafka e encontre casos de uso acionáveis — desde simples invalidação de cache até filas de tarefas robustas e leves — para ajudá-lo a escolher a ferramenta certa para suas necessidades de comunicação assíncrona.
Quando Você Deve Usar o Redis como um Message Broker?
O Redis pode ser um bom message broker quando o trabalho é pequeno, rápido e próximo dos dados que você já mantém no Redis. Também pode ser a ferramenta errada se você precisar de fortes garantias de entrega, retenção longa, recursos de roteamento ou um broker que continue funcionando confortavelmente quando o histórico de mensagens for muito maior que a memória.
A decisão fica mais fácil se você parar de perguntar "O Redis pode fazer mensageria?" e perguntar "Qual primitiva de mensageria do Redis corresponde ao modo de falha que posso tolerar?".
O Redis oferece vários padrões, mas dois são mais importantes para esta questão:
- Pub/Sub para transmissões ao vivo.
- Streams para processamento de mensagens durável, semelhante a um log, com grupos de consumidores.
Eles parecem semelhantes de longe. Não são semelhantes operacionalmente.
Use Pub/Sub quando perder uma mensagem for aceitável
O Redis Pub/Sub é uma transmissão ao vivo. Um publicador envia para um canal. Os assinantes conectados recebem a mensagem. O Redis não armazena essa mensagem para assinantes desconectados e não há confirmação integrada.
Isso é perfeito para alguns trabalhos:
SUBSCRIBE cache:invalidations
PUBLISH cache:invalidations 'product:123'
Se uma instância de aplicativo perder essa invalidação porque reiniciou no momento errado, o mundo não deve acabar. O cache local deve ter TTLs, verificações de versão ou outra forma de recuperação. Pub/Sub é um caminho de notificação, não a fonte da verdade.
Bons casos de uso do Pub/Sub:
- Invalidação de cache entre instâncias de aplicativo.
- Atualizações de UI ao vivo onde os clientes só se importam com o estado atual.
- Sinais de presença, como "usuário está digitando" ou "heartbeat do worker mudou".
- Notificações leves de implantação ou alteração de configuração.
- Eventos de fan-out onde mensagens perdidas são toleráveis.
Maus casos de uso do Pub/Sub:
- Processamento de pagamentos.
- Trabalhos de e-mail que devem eventualmente ser enviados.
- Atualizações de inventário que não devem ser ignoradas.
- Logs de auditoria.
- Qualquer coisa onde um consumidor desconectado deva recuperar o atraso mais tarde.
Pub/Sub é rápido porque faz menos. Essa é a troca.
Use Streams quando os consumidores precisam recuperar o atraso
Os Redis Streams armazenam entradas em uma estrutura de dados de stream:
XADD orders:events * order_id 42 status paid
Os consumidores podem ler a partir de uma posição:
XREAD COUNT 10 STREAMS orders:events 0
Grupos de consumidores permitem que vários workers compartilhem trabalho:
XGROUP CREATE orders:events order-workers 0 MKSTREAM
XREADGROUP GROUP order-workers worker-1 COUNT 10 STREAMS orders:events >
XACK orders:events order-workers 1740000000000-0
Com grupos de consumidores, uma mensagem entregue a um worker permanece na lista de entradas pendentes até ser confirmada com XACK. Se um worker morrer após ler, mas antes de confirmar, outro worker pode inspecionar e reivindicar o trabalho pendente. Isso oferece processamento pelo menos uma vez quando você constrói o consumidor corretamente.
Pelo menos uma vez significa que duplicatas são possíveis. Seu worker deve ser idempotente. Por exemplo, um worker de e-mail deve registrar que email_job_id=abc123 foi enviado antes de tentar enviar novamente. Um worker de pedidos deve evitar cobrar duas vezes se vir a mesma entrada de stream duas vezes.
Bons casos de uso do Streams:
- Trabalhos em segundo plano leves.
- Eventos de serviço interno que precisam de repetição após pequenas interrupções.
- Logs de eventos pequenos a médios.
- Pools de workers onde cada trabalho deve ser processado por um worker em um grupo.
- Feeds de atividade ou logs de mudança de estado com retenção limitada.
Streams não são gratuitos. As entradas vivem na memória do Redis, a menos que sejam truncadas ou expirem pelo seu design. Se você nunca truncar um stream movimentado, o stream se tornará seu próximo incidente de memória.
Use truncamento:
XADD orders:events MAXLEN ~ 100000 * order_id 42 status paid
XTRIM orders:events MAXLEN ~ 100000
O truncamento aproximado com ~ geralmente é mais barato que o truncamento exato. Escolha a retenção com base nas necessidades de recuperação, não na esperança.
As Listas do Redis ainda são úteis para filas simples
Antes dos Streams existirem, muitas filas do Redis usavam listas:
LPUSH jobs:email '{"to":"[email protected]"}'
BRPOP jobs:email 5
As listas ainda são boas para filas muito simples, especialmente quando você precisa de comportamento de pop bloqueante e não precisa de grupos de consumidores ou histórico. A limitação é a recuperação. Se um worker retirar um trabalho e falhar antes de terminar, esse trabalho é perdido, a menos que você adicione contabilidade extra.
Existem padrões usando BRPOPLPUSH ou BLMOVE para mover trabalhos para uma lista de processamento e depois removê-los após o sucesso. Esses padrões podem funcionar, mas quando você precisar de rastreamento de pendências, novas tentativas e vários consumidores, os Streams geralmente oferecem um ponto de partida mais claro.
Escolha Redis quando a simplicidade for mais importante que os recursos do broker
A mensageria Redis é atraente quando o Redis já faz parte da sua pilha e a carga de trabalho é modesta. Você evita operar outro sistema distribuído. Os desenvolvedores já entendem os clientes Redis, monitoramento, credenciais e caminhos de implantação.
Essa é uma razão válida. A simplicidade operacional tem valor real.
O Redis também tem latência muito baixa. Se seu aplicativo e o Redis estiverem na mesma região ou rede privada, publicar uma pequena notificação geralmente é barato e rápido. Para invalidação de cache ou atualizações de status ao vivo, um broker mais pesado pode ser desnecessário.
O Redis também permite combinar mudanças de estado e mensagens com cuidado. Um script Lua ou transação pode atualizar uma chave e anexar a um stream em uma única operação do lado do Redis. Isso pode ser útil para sistemas pequenos onde o Redis é o detentor central do estado.
O problema é que o Redis não deve se tornar seu acidental broker de tudo. Se todo serviço começar a adicionar streams de alto volume sem plano de retenção, a escolha "simples" se torna um armazenamento de log em memória sobrecarregado.
Escolha um broker dedicado quando o tratamento de falhas for o produto
Kafka, RabbitMQ, Pulsar, NATS JetStream e serviços de fila em nuvem existem porque a mensageria fica complicada rapidamente.
Use um broker dedicado quando precisar de recursos como:
- Retenção longa medida em semanas, meses ou anos.
- Histórico de mensagens muito maior que a memória.
- Filas de mensagens mortas e políticas de nova tentativa incorporadas ao broker.
- Entrega atrasada, prioridades, chaves de roteamento, exchanges ou particionamento de tópicos.
- Padrões de replicação entre regiões projetados para mensageria.
- Muitos grupos de consumidores independentes reproduzindo o mesmo histórico de eventos.
- Ferramentas mais robustas em torno de lag, offsets, rebalanceamento e auditorias.
O Kafka geralmente é uma escolha melhor para pipelines de eventos de alto volume e logs reproduzíveis. O RabbitMQ geralmente é uma escolha melhor para roteamento sofisticado, confirmações e filas de trabalho. As filas em nuvem geralmente são melhores quando você deseja durabilidade gerenciada e limites operacionais simples.
Os Redis Streams podem lidar com cargas de trabalho de produção úteis, mas ainda é Redis. Seus dados são centrados em memória, suas configurações de persistência devem ser compreendidas e seus recursos de broker são intencionalmente menores que os de sistemas dedicados.
Uma maneira concreta de decidir
Faça estas perguntas antes de escolher o Redis:
- Um consumidor pode perder uma mensagem sem perda de dados?
- Um consumidor desconectado precisa recuperar o atraso?
- Por quanto tempo as mensagens devem ser retidas?
- Os dados da mensagem retida cabem confortavelmente na memória do Redis?
- Os workers lidam com mensagens duplicadas com segurança?
- Você precisa de filas de mensagens mortas, novas tentativas atrasadas, prioridades ou regras de roteamento?
- Esse tráfego interferirá com o cache ou sessões do Redis?
Se mensagens perdidas forem aceitáveis, o Pub/Sub pode ser suficiente.
Se os consumidores precisarem de recuperação e a retenção for limitada, os Streams podem ser suficientes.
Se os dados da mensagem precisarem de retenção longa, reprodução por muitas equipes, comportamento complexo do broker ou forte separação operacional, use um broker dedicado.
Exemplo: invalidação de cache
Um aplicativo armazena páginas de produto na memória do processo local e no Redis. Quando um produto muda, o serviço de administração publica:
PUBLISH cache:invalidate product:123
Cada instância web inscrita em cache:invalidate exclui sua cópia local. Se uma instância web perder a mensagem, sua entrada local ainda tem um TTL de cinco minutos e também verifica um campo de versão do produto na próxima solicitação. Pub/Sub é adequado porque há um caminho de recuperação.
Usar Kafka aqui provavelmente adicionaria mais peso operacional do que valor.
Exemplo: trabalhos de e-mail em segundo plano
Um usuário se registra e você precisa enviar um e-mail de boas-vindas. Se o worker estiver inativo por um minuto, o trabalho ainda deve ser enviado mais tarde. Pub/Sub é uma escolha ruim.
Um Redis Stream pode funcionar:
XADD email:jobs MAXLEN ~ 100000 * job_id abc123 type welcome user_id 42
Os workers leem através de um grupo de consumidores, enviam o e-mail, registram job_id como concluído e chamam XACK. Um monitor verifica os trabalhos pendentes e recupera os antigos. Isso é razoável para uma fila interna modesta.
Se a entrega de e-mail se tornar em grande escala, precisar de novas tentativas atrasadas, tratamento de mensagens mortas, limites de taxa por cliente e painéis operacionais ricos, uma fila dedicada começa a parecer melhor.
Exemplo: eventos de auditoria
Eventos de auditoria geralmente precisam de durabilidade, pesquisa, retenção e, às vezes, tratamento legal ou de conformidade. Os Redis Streams podem ajudar como um buffer curto, mas o Redis não deve ser o armazenamento final de auditoria. Use um log durável, banco de dados, pipeline de armazenamento de objetos ou serviço de eventos gerenciado projetado para retenção e revisão.
Notas operacionais se você escolher o Redis
Para Pub/Sub:
- Configure
client-output-buffer-limit pubsub. - Use conexões de assinante dedicadas.
- Construa comportamento de reconexão e reassinatura.
- Trate as mensagens como dicas, não fatos duráveis.
Para Streams:
- Defina uma política de retenção com
MAXLEN,MINIDou truncamento explícito. - Monitore entradas pendentes.
- Torne os consumidores idempotentes.
- Use
XACKapenas após o trabalho ser bem-sucedido. - Planeje como mensagens paradas são reivindicadas e repetidas.
- Observe a memória, persistência e lag de replicação.
O Redis é um bom message broker quando você escolhe a parte do Redis que corresponde ao trabalho. Pub/Sub é um sinal ao vivo. Streams são um log durável limitado. Nenhum deles deve ser escolhido apenas porque o Redis já está em execução, mas ambos podem ser a resposta correta mais simples quando seu modelo de falha corresponde ao seu aplicativo.
O meio-termo desconfortável
Muitas equipes caem no meio: Pub/Sub é muito permissivo, Kafka parece grande demais e RabbitMQ parece mais um sistema para operar. Os Redis Streams podem ser uma boa resposta lá, mas apenas se você tratá-lo como uma fila real e não uma lista mágica.
Um design saudável de Streams tem propriedade em torno destes detalhes:
- Quem cria o stream e o grupo de consumidores?
- Quantos consumidores são esperados?
- Qual é a idade máxima pendente antes que uma mensagem seja reivindicada?
- O que acontece após uma falha repetida?
- Quanto histórico do stream é retido?
- Que painel ou alerta mostra o lag crescente?
Sem essas respostas, os Streams podem falhar silenciosamente. Um worker pode ler mensagens e falhar antes do XACK, deixando entradas pendentes para sempre. Outro worker pode nunca reivindicá-las. O comprimento do stream pode continuar crescendo porque ninguém configurou o truncamento. A memória do Redis aumenta, mas a equipe do aplicativo pensa "a fila é durável", então eles não percebem até que a instância esteja sob pressão.
Um worker simples geralmente deve fazer este loop:
ler um pequeno lote
processar cada mensagem de forma idempotente
confirmar apenas mensagens bem-sucedidas
inspecionar periodicamente mensagens pendentes
reivindicar mensagens pendentes paradas
truncar de acordo com a política de retenção
Isso é mais trabalho que Pub/Sub, e esse é o ponto. A durabilidade sempre move a complexidade para algum lugar. O Redis Streams mantém o lado do broker bastante pequeno, mas o aplicativo ainda é responsável por novas tentativas, comportamento de mensagens mortas e idempotência.
Se ninguém na equipe quiser ser responsável por esses detalhes, uma fila gerenciada pode ser mais barata a longo prazo, mesmo que pareça mais pesada no primeiro dia. O melhor broker não é o mais rápido em um benchmark. É aquele cujo comportamento de falha sua equipe pode operar às 3 da manhã sem adivinhar.