Direto vs. Tópico vs. Fanout: Escolhendo o Tipo de Exchange Correto

Escolha exchanges RabbitMQ direto, tópico ou fanout com base em roteamento exato, roteamento curinga ou entrega por broadcast.

Direto vs. Tópico vs. Fanout: Escolhendo o Tipo de Exchange Correto

O tipo de exchange do RabbitMQ controla para onde suas mensagens vão depois que um produtor as publica. Escolha a exchange errada e você pode acabar transmitindo trabalho privado, descartando mensagens com chaves de roteamento incompatíveis ou codificando regras de roteamento que se tornam dolorosas mais tarde.

A escolha prática é simples: use direct para roteamento exato, fanout para broadcast e topic para roteamento curinga em um esquema de nomenclatura.

Como Funciona o Roteamento no RabbitMQ

Um produtor publica em uma exchange, não diretamente em uma fila. A exchange compara a chave de roteamento da mensagem com os bindings das filas e então roteia a mensagem de acordo com o tipo de exchange.

Três termos são importantes:

  • Exchange: recebe mensagens publicadas.
  • Fila: armazena mensagens até que os consumidores as recebam.
  • Binding: conecta uma fila a uma exchange, às vezes com uma chave de binding.

Se nenhuma fila corresponder e a mensagem não estiver marcada como mandatory, o RabbitMQ pode descartar a mensagem não roteável. Para fluxos importantes, use confirmações do publicador e lide com mensagens retornadas.

Exchange Direta

Uma exchange direta roteia uma mensagem para filas cuja chave de binding corresponde exatamente à chave de roteamento da mensagem.

Use-a quando as escolhas de roteamento são conhecidas e precisas. Bons exemplos incluem severidade de log, tipo de tarefa ou filas específicas de inquilino onde nomes exatos são suficientes.

Por exemplo, vincule error_queue com error e info_queue com info. Uma mensagem publicada com a chave de roteamento error vai para error_queue; uma mensagem com info vai para info_queue. Se duas filas se vincularem com error, ambas as filas recebem uma cópia. Consumidores na mesma fila ainda competem por mensagens dessa fila.

import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
channel.exchange_declare(exchange='logs_direct', exchange_type='direct')

channel.basic_publish(
    exchange='logs_direct',
    routing_key='error',
    body=b'Falha na conexão com o banco de dados'
)

connection.close()

Escolha direto quando suas chaves de roteamento são estáveis e você não precisa de correspondência curinga.

Exchange Fanout

Uma exchange fanout roteia cada mensagem para todas as filas vinculadas à exchange. Ela ignora a chave de roteamento.

Use-a para eventos de broadcast onde cada assinante deve receber a mesma mensagem. Casos comuns incluem invalidação de cache, eventos de perfil de usuário atualizado, notificações de implantação ou atualizações de status em tempo real.

Por exemplo, uma exchange fanout user_updates pode alimentar três filas: email_queue, search_index_queue e analytics_queue. Uma atualização de perfil publicada alcança todos os três serviços.

import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
channel.exchange_declare(exchange='user_updates', exchange_type='fanout')

channel.basic_publish(
    exchange='user_updates',
    routing_key='',
    body=b'O usuário 123 alterou seu nome de exibição'
)

connection.close()

Escolha fanout quando a lógica de roteamento não importa e cada fila vinculada deve receber uma cópia.

Exchange Tópico

Uma exchange tópico roteia combinando chaves de roteamento separadas por ponto com chaves de binding curinga. Ela oferece roteamento flexível sem criar uma exchange diferente para cada tipo de evento.

Os bindings de tópico usam dois curingas:

  • * corresponde exatamente a uma palavra.
  • # corresponde a zero ou mais palavras.

Por exemplo, com chaves de roteamento como order.created.us e order.cancelled.eu:

  • order.*.us corresponde a uma ação para pedidos dos EUA.
  • order.created.# corresponde a pedidos criados em todas as regiões e palavras extras opcionais.
  • #.eu corresponde a eventos que terminam em eu.
import pika

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
channel.exchange_declare(exchange='events_topic', exchange_type='topic')

channel.basic_publish(
    exchange='events_topic',
    routing_key='order.created.us',
    body=b'Pedido 9001 criado'
)

connection.close()

Escolha tópico quando os consumidores precisam de subconjuntos filtrados de um fluxo de eventos maior, como service.environment.severity, entity.action.region ou tenant.event.priority.

Guia Rápido de Escolha

Necessidade Tipo de Exchange Exemplo
Roteamento de correspondência exata Direto error, invoice.created
Broadcast para todos os assinantes Fanout evento de limpeza de cache
Roteamento curinga Tópico orders.*.us, logs.#

Evite usar uma exchange tópico como depósito para chaves de roteamento inconsistentes. Escolha uma convenção de nomenclatura cedo, documente-a e mantenha as palavras ordenadas do geral para o específico ou da entidade para a ação, dependendo de como seus consumidores filtram.

Conclusão

Use exchanges diretas para destinos exatos, exchanges fanout para broadcast e exchanges tópico quando os consumidores precisarem de filtros curinga. Se você pode descrever a rota como um rótulo exato, use direto. Se todos precisam da mensagem, use fanout. Se os assinantes precisam de padrões, use tópico.