Что такое Exchange в RabbitMQ?

Ответ

Exchange в RabbitMQ — это сущность (виртуальный почтовый узел), которая получает сообщения от продюсеров и маршрутизирует их в одну или несколько очередей. Продюсер никогда не отправляет сообщение напрямую в очередь, он публикует его в Exchange, указывая ключ маршрутизации (routing key).

Типы Exchange и их логика маршрутизации

Тип Логика маршрутизации Аналогия
Direct Сообщение попадает в очередь, чей binding key точно совпадает с routing key сообщения. Письмо с конкретным адресом.
Fanout Сообщение копируется во все очереди, привязанные к данному Exchange. Игнорирует routing key. Радиовещание.
Topic Сообщение попадает в очередь, чей binding key соответствует шаблону routing key. Шаблоны используют символы * (одно слово) и # (ноль или несколько слов). Подписка на темы (например, logs.error.*).
Headers Маршрутизация основана на заголовках сообщения, а не на routing key. Привязка указывает условия сопоставления. Фильтрация по атрибутам.

Пример: Объявление и использование Topic Exchange на C

using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();

// 1. Объявляем Topic Exchange
channel.ExchangeDeclare(exchange: "notifications_topic",
                        type: ExchangeType.Topic,
                        durable: true);

// 2. Объявляем очереди и привязываем их с разными binding keys
channel.QueueDeclare(queue: "email_queue");
channel.QueueBind(queue: "email_queue",
                  exchange: "notifications_topic",
                  routingKey: "notifications.email.#"); // Все email-уведомления

channel.QueueDeclare(queue: "critical_queue");
channel.QueueBind(queue: "critical_queue",
                  exchange: "notifications_topic",
                  routingKey: "#.critical"); // Все критические уведомления

// 3. Публикуем сообщение с routing key
var body = Encoding.UTF8.GetBytes("Server is down!");
// Это сообщение попадет в ОБЕ очереди, т.к. ключ "notifications.email.critical"
// соответствует и "notifications.email.#", и "#.critical"
channel.BasicPublish(exchange: "notifications_topic",
                     routingKey: "notifications.email.critical",
                     basicProperties: null,
                     body: body);

Важное правило

Exchange не хранит сообщения. Если опубликованное сообщение не может быть маршрутизировано ни в одну очередь (нет подходящих привязок), оно будет безвозвратно потеряно, если не объявлен Alternate Exchange для обработки таких "сирот".

Ответ 18+ 🔞

А, слушай, про RabbitMQ и его Exchange'и — это вообще отдельная песня, блядь. Представь себе не почту, а какую-то ебанутую сортировочную станцию в голове у долбоёба. Продюсер — это ты, который принёс посылку. Ты её не суёшь прямо в ящик получателю (очередь), ты тащишь её на эту станцию (Exchange) и орёшь: «На, маршрутизируй это, сука, по такому-то ключу!». А дальше уже эта контора сама решает, в какие ящики эту хуйню пихать.

Вот какие бывают эти сортировочные конторы, ёпта:

Тип Как работает На что похоже
Direct Сообщение попадёт только в ту очередь, чей binding key полностью совпал с routing key от сообщения. Точно в цель. Как письмо с точным адресом квартиры. Не ошибёшься.
Fanout Сообщение тупо копируется во все очереди, которые к этой станции привязаны. Ключ маршрутизации всем похуй. Как радиостанция — кто включил, тот и слышит.
Topic Сообщение идёт в очередь, чей binding key подходит под шаблон ключа сообщения. Там можно звездочки * (одно слово) и решётки # (ноль или много слов) использовать. Как подписка на теги в телеге. Хочешь logs.error.* — получишь.
Headers Маршрутизация по заголовкам сообщения, а не по ключу. Привязка — это набор условий, которые надо проверить. Как фильтр в интернет-магазине: «Покажи всё красное и размера XL».

И главное, что все забывают, блядь: Exchange сообщения не хранит, сука, вообще. Это просто сортировщик-распределитель. Если твою посылку некуда деть — нет ни одной привязанной очереди, которая подходит по правилам, — то её выкинут нахуй в никуда. Насовсем. Чтобы такого не было, надо заранее «Alternate Exchange» настраивать, куда такие сиротки будут складывать. Но это уже для параноиков.

Смотри, как на C# с Topic Exchange развлекаются:

using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();

// 1. Объявляем Topic Exchange
channel.ExchangeDeclare(exchange: "notifications_topic",
                        type: ExchangeType.Topic,
                        durable: true);

// 2. Объявляем очереди и привязываем их с разными binding keys
channel.QueueDeclare(queue: "email_queue");
channel.QueueBind(queue: "email_queue",
                  exchange: "notifications_topic",
                  routingKey: "notifications.email.#"); // Все email-уведомления

channel.QueueDeclare(queue: "critical_queue");
channel.QueueBind(queue: "critical_queue",
                  exchange: "notifications_topic",
                  routingKey: "#.critical"); // Все критические уведомления

// 3. Публикуем сообщение с routing key
var body = Encoding.UTF8.GetBytes("Server is down!");
// Это сообщение попадет в ОБЕ очереди, т.к. ключ "notifications.email.critical"
// соответствует и "notifications.email.#", и "#.critical"
channel.BasicPublish(exchange: "notifications_topic",
                     routingKey: "notifications.email.critical",
                     basicProperties: null,
                     body: body);

Вот видишь? Отправил одно сообщение с ключом notifications.email.critical, а оно, хитрая жопа, улетело сразу в две очереди. Потому что шаблоны сошлись. Красота, блядь. Главное — не отправляй сообщения в Exchange, к которому ничего не привязано, а то они просто испарятся, и потом будешь ебаться, искать, куда делось.