Один узел 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 включает обратное давление:
- Блокировка отправителя — брокер ставит публикацию на паузу, если достигнут лимит памяти или диска (параметры
vm_memory_high_watermark,disk_free_limit). - Кредитная система между узлами кластера — задержка внутри кластера.
- 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:
- Кластер из трёх и более узлов в одном регионе, Quorum Queue для бизнес-сообщений.
- Federation или Shovel в резервный кластер в другом регионе для важных очередей.
- Резервная копия конфигурации через
rabbitmqctl export_definitions, в системе контроля версий. - Проверенный сценарий восстановления — не «разберёмся когда упадёт».
Коротко
- Кластер 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 — когда что выбрать.