Directo vs. Tópico vs. Fanout: Cómo elegir el tipo de intercambio adecuado

Elige intercambios directo, tópico o fanout de RabbitMQ según enrutamiento exacto, enrutamiento con comodines o entrega por difusión.

Directo vs. Tópico vs. Fanout: Cómo elegir el tipo de intercambio adecuado

El tipo de intercambio de RabbitMQ controla a dónde van tus mensajes después de que un productor los publique. Elegir el intercambio incorrecto puede llevar a difundir trabajo privado, perder mensajes con claves de enrutamiento no coincidentes o codificar reglas de enrutamiento que se vuelvan difíciles de mantener más adelante.

La elección práctica es simple: usa direct para enrutamiento exacto, fanout para difusión y topic para enrutamiento con comodines en un esquema de nombres.

Cómo funciona el enrutamiento en RabbitMQ

Un productor publica en un intercambio, no directamente en una cola. El intercambio compara la clave de enrutamiento del mensaje con los enlaces de las colas y luego enruta el mensaje según el tipo de intercambio.

Tres términos importantes:

  • Intercambio: recibe los mensajes publicados.
  • Cola: almacena mensajes hasta que los consumidores los reciben.
  • Enlace: conecta una cola a un intercambio, a veces con una clave de enlace.

Si ninguna cola coincide y el mensaje no está marcado como mandatory, RabbitMQ puede descartar el mensaje no enrutable. Para flujos importantes, usa confirmaciones de publicación y maneja los mensajes devueltos.

Intercambio directo

Un intercambio directo enruta un mensaje a las colas cuya clave de enlace coincide exactamente con la clave de enrutamiento del mensaje.

Úsalo cuando las opciones de enrutamiento sean conocidas y precisas. Buenos ejemplos incluyen severidad de registros, tipo de tarea o colas específicas de inquilinos donde los nombres exactos son suficientes.

Por ejemplo, enlaza error_queue con error y info_queue con info. Un mensaje publicado con la clave de enrutamiento error va a error_queue; un mensaje con info va a info_queue. Si dos colas se enlazan con error, ambas reciben una copia. Los consumidores en la misma cola aún compiten por los mensajes de esa cola.

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'Conexión a base de datos fallida'
)

connection.close()

Elige directo cuando tus claves de enrutamiento sean estables y no necesites coincidencias con comodines.

Intercambio fanout

Un intercambio fanout enruta cada mensaje a todas las colas enlazadas al intercambio. Ignora la clave de enrutamiento.

Úsalo para eventos de difusión donde cada suscriptor debe recibir el mismo mensaje. Casos comunes incluyen invalidación de caché, eventos de perfil de usuario actualizado, notificaciones de despliegue o actualizaciones de estado en tiempo real.

Por ejemplo, un intercambio fanout user_updates podría alimentar tres colas: email_queue, search_index_queue y analytics_queue. Una actualización de perfil publicada llega a los tres servicios.

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'El usuario 123 cambió su nombre de pantalla'
)

connection.close()

Elige fanout cuando la lógica de enrutamiento no importe y cada cola enlazada deba recibir una copia.

Intercambio tópico

Un intercambio tópico enruta mediante la coincidencia de claves de enrutamiento separadas por puntos con claves de enlace con comodines. Te da un enrutamiento flexible sin crear un intercambio diferente para cada tipo de evento.

Los enlaces de tópico usan dos comodines:

  • * coincide exactamente con una palabra.
  • # coincide con cero o más palabras.

Por ejemplo, con claves de enrutamiento como order.created.us y order.cancelled.eu:

  • order.*.us coincide con una acción para pedidos de EE. UU.
  • order.created.# coincide con pedidos creados en todas las regiones y palabras adicionales opcionales.
  • #.eu coincide con eventos que terminan en 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 creado'
)

connection.close()

Elige tópico cuando los consumidores necesiten subconjuntos filtrados de un flujo de eventos más grande, como servicio.entorno.severidad, entidad.accion.region o inquilino.evento.prioridad.

Guía rápida de elección

Necesidad Tipo de intercambio Ejemplo
Enrutamiento de coincidencia exacta Directo error, invoice.created
Difusión a cada suscriptor Fanout evento de purga de caché
Enrutamiento con comodines Tópico orders.*.us, logs.#

Evita usar un intercambio tópico como vertedero de claves de enrutamiento inconsistentes. Elige una convención de nombres temprano, documéntala y mantén las palabras ordenadas de lo general a lo específico o de entidad a acción, según cómo filtren tus consumidores.

Conclusión

Usa intercambios directos para destinos exactos, intercambios fanout para difusión e intercambios tópicos cuando los consumidores necesiten filtros con comodines. Si puedes describir la ruta como una etiqueta exacta, usa directo. Si todos necesitan el mensaje, usa fanout. Si los suscriptores necesitan patrones, usa tópico.