← назад к разделу

Один узел RabbitMQ хорошо работает на ноутбуке. На проде всё сложнее: нужно пережить перезапуск сервера, не потерять сообщения, мониторить здоровье брокера. Разберём, как RabbitMQ устроен в реальном окружении.

Зачем нужен кластер

Представьте: ваш сервер с RabbitMQ перезагрузился. Все сообщения, которые ждали обработки, пропали. Все приложения, которые писали в очередь, получили ошибку соединения. Пока сервер не поднялся — система не работает.

Кластер решает эту проблему: несколько узлов RabbitMQ работают вместе и знают друг о друге. Если один узел упал, остальные продолжают принимать и отдавать сообщения.

Как устроен кластер. Все узлы кластера хранят одинаковые метаданные: описания обменников, очередей, привязок, пользователей. Эти метаданные синхронизируются автоматически — через Raft (с версии 3.10) или Mnesia (в старых версиях).

Клиент может подключиться к любому узлу кластера. Если нужная очередь живёт на другом узле — текущий узел сам перенаправит запрос.

Несколько важных следствий:

  • Минимум 3 узла для надёжной работы. С двумя узлами при потере одного второй уходит в режим только для чтения и кластер перестаёт принимать новые сообщения.
  • Сетевой разрыв между узлами (split brain) — серьёзная проблема. RabbitMQ умеет несколько стратегий поведения (pause-minority, autoheal, ignore), но ни одна не проходит без последствий. Правильный выбор типа очереди снижает риски.
  • Сама очередь физически живёт на одном узле (Classic) или реплицируется по нескольким (Quorum, Streams). Это главное архитектурное решение.

Три типа очередей

Classic Queue

Самый старый тип, существует с первых версий RabbitMQ. По умолчанию очередь не реплицируется — она живёт на одном узле. Если этот узел упал, очередь недоступна до его возврата.

Раньше Classic Queue можно было «зеркалировать» на другие узлы через политику ha-mode. Этот механизм отмечен устаревшим в версии 3.8 и полностью удалён в 4.0. В новом коде его использовать нельзя.

Когда Classic Queue уместна сейчас:

  • Временные очереди: RPC-ответы, уведомления без гарантий, кэш-инвалидация.
  • Ситуации, где потеря сообщения допустима: метрики, неважные события.
  • Не подходит для: заказов, платежей, любых бизнес-событий.

Quorum Queue

Появились в версии 3.8, стали стандартом с 3.10. Это очередь, которая реплицируется по нескольким узлам через алгоритм Raft: один узел — лидер, остальные — последователи. Сообщение считается сохранённым только когда большинство реплик его получили.

channel.queue_declare(
    queue="orders",
    durable=True,
    arguments={"x-queue-type": "quorum"}
)

Свойства:

  • Высокая доступность. При обычной конфигурации (3 узла) потеря одного не влияет на работу. Потеря двух — очередь недоступна до возврата узла.
  • Надёжное хранение. Каждое сообщение реплицировано на большинство узлов до подтверждения отправителю.
  • Дороже Classic. Больше операций ввода-вывода, больше памяти. На небольших объёмах избыточно; на критичных данных — обязательно.
  • Ограничения. Нет приоритетных очередей, нет эксклюзивных очередей, нет временных сообщений.

Quorum Queue — выбор по умолчанию для всего, что нельзя терять.

Streams

Появились в версии 3.9. Это журнал сообщений — append-only лог, реплицированный через Raft, с возможностью читать с любого смещения.

channel.queue_declare(
    queue="events-log",
    durable=True,
    arguments={
        "x-queue-type": "stream",
        "x-max-length-bytes": 10_000_000_000  # 10 GB хранения
    }
)

Подходит, когда:

  • Нужно переиграть историю: новый сервис хочет прочитать события за прошлую неделю.
  • Одни и те же сообщения читают несколько независимых потребителей без копирования.
  • Нужен высокий поток данных (миллионы сообщений в секунду).

Не подходит для: маршрутизации по заголовкам и паттернам, RPC-сценариев, dead-letter-маршрутизации.

Если задача чисто журнальная и нужна производительность уровня Kafka — скорее всего лучше Kafka. Streams полезны, когда уже есть инфраструктура RabbitMQ и не хочется добавлять ещё одну систему.

Хранение сообщений и память

Постоянное (persistent) сообщение в Classic или Quorum Queue пишется на диск. Но при этом оно также держится в памяти — для быстрой отдачи потребителю.

В Classic Queue был специальный режим lazy queue: сообщения сразу пишутся на диск и не занимают память. Он применялся, когда очередь могла накопить миллионы сообщений. С появлением Quorum Queue в этом режиме нет необходимости — там поведение регулируется через параметр x-max-in-memory-length.

В новых проектах: Quorum Queue с настройкой x-max-in-memory-length под нагрузку.

Репликация между регионами

Кластеризация RabbitMQ не предназначена для узлов в разных регионах. Raft требует низких задержек внутри кластера. Соединение через регионы с задержкой больше 10 мс ведёт к нестабильности и разделению кластера.

Для географически распределённых систем используют отдельные кластеры в каждом регионе и один из двух инструментов переноса сообщений между ними:

Federation — связь обменник-к-обменнику или очередь-к-очереди между кластерами. Сообщения публикуются в одном кластере и асинхронно копируются в другой. Кластеры независимы друг от друга.

Shovel — простой «насос»: читает из исходной очереди, публикует в целевой обменник. Удобен для разовых переносов и сценариев точка-точка.

При полном падении основного кластера: приложения переключаются на резервный, теряется максимум задержка репликации (обычно несколько секунд).

Обратное давление и flow control

Когда очередь растёт быстрее, чем обрабатывается, RabbitMQ включает обратное давление:

  1. Блокировка отправителя — брокер ставит публикацию на паузу, если достигнут лимит памяти или диска (параметры vm_memory_high_watermark, disk_free_limit).
  2. Кредитная система между узлами кластера — задержка внутри кластера.
  3. Prefetch на стороне потребителя — ограничение числа сообщений без подтверждения.

Когда сработала блокировка — публикация тормозится синхронно. Сервис, который писал «отправил и забыл», начинает получать задержки или таймауты. Это правильное поведение брокера, но приложение должно уметь с этим работать: передавать давление выше по цепочке, ограничивать входящий поток, использовать запасной сценарий.

Мониторинг

RabbitMQ экспортирует метрики в формате Prometheus. Ключевые показатели:

МетрикаЧто значитКогда беспокоиться
rabbitmq_queue_messages_readyСообщений ждёт обработкиРастёт и не падает
rabbitmq_queue_messages_unackedВыдано потребителям без подтвержденияПревышает prefetch × число потребителей × 2
rabbitmq_node_mem_used / rabbitmq_node_mem_limitИспользование памятиВыше 80%
rabbitmq_node_disk_freeСвободное место на дискеМеньше 1 ГБ
rabbitmq_queue_consumersЧисло активных потребителейНоль при ожидаемом ≥ 1
rabbitmq_connectionsОткрытые соединенияРезкий скачок или полный ноль

Главное — следить за соотношением messages_ready и пропускной способностью потребителей. Это аналог Kafka consumer lag: если очередь только растёт, система не справляется.

Ориентиры по производительности

Грубые цифры для одного современного сервера (8 ядер, 32 ГБ памяти, NVMe):

  • Quorum Queue с постоянным хранением: 30–50 тысяч сообщений в секунду.
  • Classic Queue без постоянного хранения: 100+ тысяч сообщений в секунду.
  • Оптимальный размер сообщения: 1–10 КБ. Сообщения больше 100 КБ заметно снижают производительность; больше 1 МБ лучше хранить в объектном хранилище и передавать только ссылку.
  • Число очередей: тысячи — норма, десятки тысяч — нагрузка на метаданные, сотни тысяч — рискованно.

Базовая стратегия надёжности

Для критичного сервиса на RabbitMQ:

  1. Кластер из трёх и более узлов в одном регионе, Quorum Queue для бизнес-сообщений.
  2. Federation или Shovel в резервный кластер в другом регионе для важных очередей.
  3. Резервная копия конфигурации через rabbitmqctl export_definitions, в системе контроля версий.
  4. Проверенный сценарий восстановления — не «разберёмся когда упадёт».

Коротко

  • Кластер RabbitMQ = несколько узлов с общими метаданными. Минимум 3 узла для надёжной работы.
  • Classic Queue — без репликации, для временных и некритичных сообщений. Mirroring удалён в версии 4.0.
  • Quorum Queue — стандарт для бизнес-данных; репликация через Raft, сообщение подтверждено только когда большинство узлов его получили.
  • Streams — журнал с возможностью переигрывания; подходит для высокого потока и нескольких независимых читателей.
  • Кластеризация не работает между регионами с высокой задержкой — для этого есть Federation и Shovel.
  • При переполнении брокер блокирует отправку — приложение должно уметь с этим работать.
  • Ключевая метрика — рост messages_ready без уменьшения: очередь накапливается.

Что почитать дальше

  • Протокол AMQP — модель доставки, обменники, очереди, binding.
  • Spring AMQP — как писать клиентский код на Java.
  • Паттерны через AMQP — work queue, pub/sub, RPC.
  • AMQP против Kafka — когда что выбрать.