Ответ
Маршрутизация сообщений в RabbitMQ — это механизм, с помощью которого обменник (exchange) решает, в какие очереди (queues) отправить поступившее сообщение. Логика маршрутизации определяется типом обменника и привязками (bindings) между обменником и очередями.
Основные типы обменников и их логика маршрутизации:
-
Direct Exchange (Прямой)
- Принцип: Сообщение отправляется в очереди, чей ключ маршрутизации (routing key) полностью совпадает с routing key сообщения.
- Использование: Точечная отправка, задачи по типу (например,
logs.error,orders.process).// Объявление обменника channel.ExchangeDeclare(exchange: "direct_logs", type: ExchangeType.Direct); // Привязка очереди с ключом "error" channel.QueueBind(queue: "queue_errors", exchange: "direct_logs", routingKey: "error"); // Публикация. Сообщение попадёт ТОЛЬКО в очередь "queue_errors" channel.BasicPublish(exchange: "direct_logs", routingKey: "error", basicProperties: null, body: messageBody);
-
Fanout Exchange (Широковещательный)
- Принцип: Сообщение копируется и отправляется во ВСЕ привязанные к обменнику очереди. Routing key игнорируется.
- Использование: Широковещательные уведомления, обновления кэша для всех инстансов приложения.
channel.ExchangeDeclare(exchange: "fanout_updates", type: ExchangeType.Fanout); // Сообщение будет отправлено во все привязанные очереди (queue_a, queue_b, ...) channel.BasicPublish(exchange: "fanout_updates", routingKey: "", basicProperties: null, body: messageBody);
-
Topic Exchange (Топический)
- Принцип: Маршрутизация по шаблону. Routing key сообщения (например,
"quick.orange.rabbit") сопоставляется с шаблоном ключа в привязке, который может содержать подстановочные знаки:*(звездочка) — заменяет ровно одно слово.#(решетка) — заменяет ноль или более слов.
- Использование: Сложные системы подписок, фильтрация событий по категориям.
channel.ExchangeDeclare(exchange: "topic_logs", type: ExchangeType.Topic); channel.QueueBind(queue: "queue_all_errors", exchange: "topic_logs", routingKey: "*.error"); channel.QueueBind(queue: "queue_critical", exchange: "topic_logs", routingKey: "critical.#"); // Сообщение с ключом "app.error" попадёт в queue_all_errors // Сообщение с ключом "critical.system.database" попадёт в queue_critical
- Принцип: Маршрутизация по шаблону. Routing key сообщения (например,
-
Headers Exchange (Заголовочный)
- Принцип: Маршрутизация происходит на основе заголовков сообщения (headers), а не routing key. Привязка задаёт условия сопоставления (
x-match: all— все заголовки должны совпасть,x-match: any— достаточно любого).
- Принцип: Маршрутизация происходит на основе заголовков сообщения (headers), а не routing key. Привязка задаёт условия сопоставления (
Важное замечание: Обменники не хранят сообщения. Если на момент публикации сообщения нет ни одной очереди, удовлетворяющей правилам маршрутизации, сообщение будет безвозвратно утеряно, если не установлен флаг mandatory. Для обработки таких случаев используется механизм возвратов (Returned Messages).
Ответ 18+ 🔞
А, маршрутизация в RabbitMQ! Ну это, блядь, как почтальоны в нашем подъезде разбираются, кому какую хуйню в ящик пихать. Сейчас разжуёшь, только не обосрись от восторга.
Смотри, есть у тебя обменник (exchange) — это такой главный распределительный щит, куда все сообщения приходят. А его задача — решить, в какую очередь (queue) эту посылку отправить. Логика этого цирка зависит от того, какой у тебя обменник.
Вот основные типы, и как они работают:
-
Direct Exchange (Прямой)
- Суть: Всё просто, как три копейки. Сообщение полетит только в ту очередь, чей ключ маршрутизации (routing key) полностью совпадает с ключом в сообщении. Точно в цель, без промаха.
- Зачем: Когда нужно чётко раскидать задачи по типам. Типа
logs.error— в одну кучу,orders.process— в другую.// Объявляем обменник, говорим, что он прямой channel.ExchangeDeclare(exchange: "direct_logs", type: ExchangeType.Direct); // Привязываем очередь "queue_errors" к нему с ключом "error" channel.QueueBind(queue: "queue_errors", exchange: "direct_logs", routingKey: "error"); // Публикуем с ключом "error". Сообщение прилетит ТОЛЬКО в "queue_errors", больше никуда. channel.BasicPublish(exchange: "direct_logs", routingKey: "error", basicProperties: null, body: messageBody);
-
Fanout Exchange (Широковещательный)
- Суть: А вот это уже раздолбайство полное. Получил сообщение — и хуяк его копии во ВСЕ очереди, что к нему привязаны. Routing key тут вообще игнорируется, как будто его нет. Всё равно что крикнуть в подъезде — услышат все, кому не лень.
- Зачем: Для рассылки уведомлений всем подряд, или чтобы обновить кэш на всех инстансах приложения.
channel.ExchangeDeclare(exchange: "fanout_updates", type: ExchangeType.Fanout); // Сообщение уйдёт в queue_a, queue_b, queue_c... короче, во все, что привязаны. Ключ можешь хоть "попугай" писать. channel.BasicPublish(exchange: "fanout_updates", routingKey: "", basicProperties: null, body: messageBody);
-
Topic Exchange (Топический)
- Суть: А это для умников, которые любят шаблоны. Тут routing key сообщения (например,
"quick.orange.rabbit") сравнивается с шаблоном в привязке. В шаблоне можно дикие карты использовать:*(звездочка) — заменяет ровно ОДНО слово. Не больше, не меньше.#(решетка) — заменяет ноль, одно, десять или овердохуища слов. Жадная сука.
- Зачем: Для сложных систем подписок. Типа "мне всё про ошибки" или "только критические сообщения любой вложенности".
channel.ExchangeDeclare(exchange: "topic_logs", type: ExchangeType.Topic); // Вяжем очередь для всех ошибок: *.error (первое слово — любое, второе — error) channel.QueueBind(queue: "queue_all_errors", exchange: "topic_logs", routingKey: "*.error"); // Вяжем очередь для всего критического: critical.# (слово critical, а дальше что угодно или ничего) channel.QueueBind(queue: "queue_critical", exchange: "topic_logs", routingKey: "critical.#"); // Ключ "app.error" — попадёт в queue_all_errors. // Ключ "critical.system.database" — попадёт в queue_critical.
- Суть: А это для умников, которые любят шаблоны. Тут routing key сообщения (например,
-
Headers Exchange (Заголовочный)
- Суть: Вообще отбитая штука. Тут маршрутизация идёт по заголовкам сообщения (headers), а на routing key всем насрать. В привязке задаёшь условия:
x-match: all— чтобы ВСЕ заголовки совпали,x-match: any— чтобы хватило ЛЮБОГО совпадения.
- Суть: Вообще отбитая штука. Тут маршрутизация идёт по заголовкам сообщения (headers), а на routing key всем насрать. В привязке задаёшь условия:
И главное, запомни раз и нахуй: обменники — это не склады! Они сообщения не хранят. Если ты отправил сообщение, а на момент отправки нет ни одной очереди, которая подходит под правила — сообщение просто сгорает, нахуй. Исключение — если выставил специальный флаг mandatory, тогда неудачные сообщения можно будет поймать через механизм возвратов (Returned Messages). Но это уже другая история, ебать её в сраку.