¿Cuáles son los tipos de exchange de RabbitMQ — direct, topic, fanout, headers — y cuándo usar cada uno?
RabbitMQ enruta todo mensaje a través de un exchange, y el tipo de exchange — direct, topic, fanout o headers — decide qué colas lo reciben realmente.
APRENDE HACIENDOPon a prueba tu intuición3 pasos
¿Cuáles son los tipos de exchange de RabbitMQ — direct, topic, fanout, headers — y cuándo usar cada uno?
Usa los ejemplos y la explicación de la lección para comprobar tu idea.
Reflexión personal. No se envía a ningún servicio de IA.En RabbitMQ, un productor nunca publica directamente en una cola: publica un mensaje en un exchange, y es el exchange quien decide qué cola (o colas) reciben realmente una copia, según los bindings. Un binding conecta un exchange con una cola, opcionalmente con una routing key o un patrón de headers. Esa indirección es lo que hace que el enrutamiento de RabbitMQ sea lo bastante flexible como para modelar entregas directas, topics jerárquicos, broadcasts y filtros multi-atributo — todo con el mismo primitivo central.
#Los cuatro tipos de exchange
| Tipo de exchange | Lógica de enrutamiento | Caso de uso típico |
|---|---|---|
| direct | Coincidencia exacta entre la routing key del mensaje y la binding key de una cola | Enrutar a un tipo de consumidor conocido (p. ej. email, sms) |
| topic | Coincidencia de patrón sobre una routing key separada por puntos, usando * (una palabra) y # (cero o más palabras) | Enrutamiento jerárquico, p. ej. severidad de log + nombre de servicio |
| fanout | Ignora la routing key por completo — entrega a todas las colas enlazadas | Broadcast a todos los suscriptores, p. ej. invalidación de caché |
| headers | Coincide sobre pares clave/valor de los headers del mensaje, no sobre la routing key | Enrutar según varios atributos independientes que no caben en una sola clave |
#Exchange direct
Un exchange direct es el más simple: un mensaje con routing key email va a toda cola enlazada con la binding key email, y a ninguna otra. Se comporta como una búsqueda en un diccionario — útil cuando tienes un conjunto pequeño y conocido de categorías de mensaje y quieres que cada una la maneje un pool de workers dedicado.
import pikaconnection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))channel = connection.channel()channel.exchange_declare(exchange='notifications.direct', exchange_type='direct')channel.queue_declare(queue='email_queue')channel.queue_declare(queue='sms_queue')channel.queue_bind(exchange='notifications.direct', queue='email_queue', routing_key='email')channel.queue_bind(exchange='notifications.direct', queue='sms_queue', routing_key='sms')channel.basic_publish(exchange='notifications.direct',routing_key='email', # se entrega solo a email_queuebody='{"to": "user@example.com", "template": "welcome"}')
El exchange por defecto (el exchange sin nombre "" que tiene todo vhost de RabbitMQ) es un caso especial de enrutamiento direct donde la routing key se trata directamente como el nombre de la cola — por eso basic_publish(exchange='', routing_key='my_queue', ...) parece "publicar directo en una cola", aunque en realidad sigue pasando por un exchange.
#Exchange topic
Un exchange topic generaliza el enrutamiento direct con coincidencia de comodines sobre una routing key separada por puntos. * coincide con exactamente una palabra en esa posición; # coincide con cero o más palabras. Es el tipo de exchange al que recurrir cuando las routing keys son jerárquicas por naturaleza.
channel.exchange_declare(exchange='logs.topic', exchange_type='topic')channel.queue_declare(queue='payment_errors')channel.queue_declare(queue='all_logs')channel.queue_bind(exchange='logs.topic', queue='payment_errors', routing_key='logs.error.*')channel.queue_bind(exchange='logs.topic', queue='all_logs', routing_key='logs.#')channel.basic_publish(exchange='logs.topic',routing_key='logs.error.payment-service', # coincide con AMBOS bindings de arribabody='Payment gateway timeout')
Un solo publish puede coincidir con varios bindings a la vez — aquí, tanto payment_errors como all_logs reciben una copia, porque ambos patrones coinciden con logs.error.payment-service.
#Exchange fanout
Un exchange fanout ignora la routing key por completo y entrega cada mensaje a todas las colas enlazadas a él. Es el equivalente de RabbitMQ a un broadcast — útil en escenarios pub/sub donde cada suscriptor necesita su propia copia de cada evento, como invalidar una caché en memoria en todas las instancias en ejecución de un servicio.
channel.exchange_declare(exchange='cache.invalidate', exchange_type='fanout')for instance_queue in ['api_instance_1', 'api_instance_2', 'api_instance_3']:channel.queue_declare(queue=instance_queue, exclusive=True)channel.queue_bind(exchange='cache.invalidate', queue=instance_queue) # no hace falta routing keychannel.basic_publish(exchange='cache.invalidate', routing_key='', body='invalidate:user:42')
Nota que cada instancia se enlaza a su propia cola exclusiva, normalmente autogenerada — eso es lo que convierte un fanout en "cada listener recibe una copia" en vez del patrón de consumidores compitiendo (competing consumers) que obtendrías si todas las instancias compartieran una sola cola.
#Exchange headers
Un exchange headers enruta según los atributos del header del mensaje en lugar de la routing key, usando un argumento x-match de all (todos los headers listados deben coincidir) o any (basta con que coincida al menos uno). Es el tipo menos usado, reservado para casos en los que el enrutamiento depende de varios atributos independientes que no se comprimen bien en un solo string de routing key.
channel.exchange_declare(exchange='orders.headers', exchange_type='headers')channel.queue_declare(queue='high_value_us_orders')channel.queue_bind(exchange='orders.headers',queue='high_value_us_orders',arguments={'x-match': 'all', 'country': 'US', 'tier': 'high-value'})channel.basic_publish(exchange='orders.headers',routing_key='', # ignorado por los exchanges de tipo headersbody='{"orderId": 981, "total": 4200}',properties=pika.BasicProperties(headers={'country': 'US', 'tier': 'high-value'}))