Что такое RabbitMQ?

«Что такое RabbitMQ?» — вопрос из категории Брокеры сообщений, который задают на 28% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

RabbitMQ — это популярный опенсорсный брокер сообщений, реализующий и расширяющий протокол AMQP (Advanced Message Queuing Protocol). Он выступает в роли промежуточного слоя (middleware), который принимает, хранит, маршрутизирует и доставляет сообщения между независимыми приложениями или сервисами.

Решаемые проблемы:

  • Связность (Decoupling): Отправитель (Producer) и получатель (Consumer) не знают друг о друге и работают асинхронно.
  • Буферизация (Buffering): Брокер накапливает сообщения, если потребитель временно не готов, сглаживая пиковые нагрузки.
  • Гарантированная доставка (Reliability): Подтверждения (acknowledgements), persistence сообщений на диск.
  • Гибкая маршрутизация (Routing): Разные типы обменников (exchanges) позволяют реализовать сложные сценарии (публикация/подписка, маршрутизация по ключу).

Базовая архитектура AMQP в RabbitMQ:

Producer --> Exchange --(Binding/Routing Key)--> Queue --> Consumer
  • Exchange получает сообщения от продюсера и решает, в какие очереди их направить. Основные типы:
    • direct (доставка по точному совпадению ключа маршрутизации).
    • fanout (рассылка во все привязанные очереди).
    • topic (доставка по шаблону ключа).
    • headers (доставка по заголовкам сообщения).
  • Queue — это именованный буфер, хранящий сообщения до их обработки потребителем.
  • Binding — это правило, связывающее exchange с очередью.

Пример на C# (с использованием библиотеки RabbitMQ.Client):

// 1. PRODUCER (Отправка лога)
using RabbitMQ.Client;

var factory = new ConnectionFactory() { HostName = "localhost" };
using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();

// Объявляем exchange типа 'direct' с именем 'logs'
channel.ExchangeDeclare(exchange: "logs", type: ExchangeType.Direct);

var severity = "error"; // Ключ маршрутизации
var message = $"[{DateTime.UtcNow}] Critical error in module X.";
var body = Encoding.UTF8.GetBytes(message);

// Публикуем сообщение в exchange 'logs' с ключом 'error'
channel.BasicPublish(exchange: "logs",
                     routingKey: severity,
                     basicProperties: null,
                     body: body);
Console.WriteLine($" [x] Sent '{severity}':'{message}'");

// 2. CONSUMER (Получение только ошибок)
// ... (создание connection и channel аналогично)
// Объявляем тот же exchange
channel.ExchangeDeclare(exchange: "logs", type: ExchangeType.Direct);
// Создаём временную (exclusive) очередь с автоматическим именем
var queueName = channel.QueueDeclare().QueueName;
// Привязываем очередь к exchange 'logs' с ключом 'error'
channel.QueueBind(queue: queueName,
                  exchange: "logs",
                  routingKey: "error");

var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
    var receivedBody = ea.Body.ToArray();
    var receivedMessage = Encoding.UTF8.GetString(receivedBody);
    Console.WriteLine($" [x] Received '{ea.RoutingKey}':'{receivedMessage}'");
    // Ручное подтверждение обработки
    channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
};
// Начинаем потребление с отключением autoAck
channel.BasicConsume(queue: queueName,
                     autoAck: false, // Важно для надёжности!
                     consumer: consumer);

Почему RabbitMQ? Он обеспечивает надёжную, гибкую и кросс-платформенную коммуникацию между сервисами, что является фундаментом для архитектур, основанных на микросервисах и событиях (Event-Driven Architecture).