Ответ
Headers Exchange — это особый тип обменника (exchange) в RabbitMQ, который маршрутизирует сообщения не по ключу маршрутизации (routing key), а на основе заголовков (headers) — пары ключ-значение в свойствах сообщения. Это позволяет реализовать сложную логику маршрутизации, основанную на нескольких атрибутах.
Сравнение с другими типами exchange:
| Тип Exchange | Основа маршрутизации | Пример использования |
|---|---|---|
| Direct | Точное совпадение routing key | Распределение задач по типам (task.image, task.pdf) |
| Topic | Шаблон routing key (*, #) |
События по иерархии (logs.app.error, user.registered) |
| Fanout | Без маршрутизации (все очереди) | Широковещательные уведомления |
| Headers | Совпадение заголовков сообщения | Фильтрация по атрибутам (format=json, version=2, priority=high) |
Ключевой параметр: x-match
При привязке очереди к Headers Exchange указывается аргумент x-match, который определяет логику сопоставления:
x-match = all(по умолчанию): Все пары ключ-значение в аргументах привязки должны присутствовать и совпадать со заголовками сообщения (логическое И).x-match = any: Достаточно совпадения хотя бы одной пары ключ-значение (логическое ИЛИ).
Пример на C# (с использованием библиотеки RabbitMQ.Client):
using RabbitMQ.Client;
using System.Text;
using System.Text.Json;
// 1. Создание соединения и канала
var factory = new ConnectionFactory { HostName = "localhost" };
using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();
// 2. Объявление Headers Exchange
channel.ExchangeDeclare(exchange: "notifications_headers", type: ExchangeType.Headers, durable: true);
// 3. Объявление очередей и привязка с разными условиями
// Очередь для JSON-уведомлений высокой важности
channel.QueueDeclare("queue_critical_json", durable: true, exclusive: false, autoDelete: false);
var criticalBindArgs = new Dictionary<string, object>
{
{ "format", "json" },
{ "priority", "high" },
{ "x-match", "all" } // ДОЛЖНЫ быть ОБА заголовка: format=json И priority=high
};
channel.QueueBind(queue: "queue_critical_json", exchange: "notifications_headers", routingKey: "", arguments: criticalBindArgs);
// Очередь для любых XML-уведомлений ИЛИ уведомлений с тегом "legacy"
channel.QueueDeclare("queue_general", durable: true, exclusive: false, autoDelete: false);
var generalBindArgs = new Dictionary<string, object>
{
{ "format", "xml" },
{ "tag", "legacy" },
{ "x-match", "any" } // Достаточно format=xml ИЛИ tag=legacy
};
channel.QueueBind(queue: "queue_general", exchange: "notifications_headers", routingKey: "", arguments: generalBindArgs);
// 4. Публикация сообщения с заголовками
var message = new { Text = "Важное событие!" };
var body = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(message));
var properties = channel.CreateBasicProperties();
properties.Persistent = true;
properties.Headers = new Dictionary<string, object>
{
{ "format", "json" },
{ "priority", "high" },
{ "source", "api" }
};
// Сообщение будет доставлено ТОЛЬКО в очередь "queue_critical_json",
// так как совпали ВСЕ требуемые заголовки (format=json, priority=high).
// В "queue_general" оно не попадет, так как нет ни format=xml, ни tag=legacy.
channel.BasicPublish(exchange: "notifications_headers",
routingKey: "", // Для Headers Exchange routing key игнорируется или может быть пустым
basicProperties: properties,
body: body);
Когда использовать Headers Exchange?
- Сложная фильтрация: Когда для маршрутизации нужны несколько независимых критериев (например,
версия API=2,регион=EU,тип клиента=premium). - Маршрутизация по атрибутам, а не по теме: Если логика не укладывается в иерархическую структуру Topic Exchange.
- Динамическая подписка: Клиенты могут гибко настраивать, сообщения с каким набором атрибутов они хотят получать.
Недостаток:
Маршрутизация по заголовкам менее эффективна, чем по routing key, так как требует сопоставления хэш-таблиц. Для высоконагруженных систем с простой логикой Direct или Topic Exchange предпочтительнее.