Мониторинг и кластеризация
Как за четыре числа понять, что брокеру плохо, — и что даёт кластер, кроме иллюзии надёжности.
Здоровье очереди определяется не её размером, а производной: растёт длина или падает. Очередь на 100 000 сообщений, которая уменьшается, — норма. Очередь на 300 сообщений, которая растёт третий час, — авария.
Четыре числа, которые надо знать наизусть
В панели RabbitMQ десятки метрик, но в 90% инцидентов ответ находится в этих четырёх.
| Метрика | Что значит | О чём говорит рост |
messages_ready | Лежат в очереди, ждут потребителя | Потребители не справляются или их нет вовсе |
messages_unacknowledged | Отданы потребителю, но ack ещё не пришёл | Обработчик завис. Если число равно prefetch × число потребителей и не меняется — потребитель мёртв, но соединение живо |
publish rate / ack rate | Сообщений в секунду на входе и на выходе | Если publish устойчиво больше ack — очередь будет расти вечно. Это единственное неравенство, которое надо отслеживать |
consumers | Сколько потребителей подписано | Ноль на рабочей очереди — самая частая причина «сообщения не доходят» |
Из этих чисел выводится главный практический показатель — за сколько разгребётся затор. Считается элементарно, но именно этой цифры обычно не хватает в три часа ночи, когда надо решать, ждать или срочно поднимать потребителей.
ready = 128_400 # сообщений накопилось в очереди
publish_rate = 320.0 # приходит в секунду
ack_rate = 410.0 # обрабатывается в секунду
drain = ack_rate - publish_rate
if drain <= 0:
print('Очередь не разбирается: потребители медленнее издателей.')
print('Ждать бесполезно — нужно добавлять потребителей.')
else:
seconds = ready / drain
print(f'Чистая скорость разбора: {drain:.0f} сообщений/с')
print(f'Очередь опустеет примерно через {seconds / 60:.1f} мин')
Результат:
Чистая скорость разбора: 90 сообщений/с
Очередь опустеет примерно через 23.8 мин
Поменяйте ack_rate на 300 — и увидите второй сценарий: разрыв не закроется никогда, сколько ни жди.
Где всё это смотреть
Четыре инструмента, от простого к боевому.
1. Панель управления. Включается плагином, живёт на порту 15672. Показывает очереди, скорости, соединения, каналы, позволяет заглянуть в сообщение (Get messages) и опубликовать тестовое. Незаменима при разборе инцидента, но для постоянного наблюдения не годится: истории она почти не хранит.
rabbitmq-plugins enable rabbitmq_management
# панель: http://localhost:15672 (по умолчанию guest/guest, только с localhost)
2. CLI. Первое, что запускают по ssh, когда «всё встало».
# Кто копит сообщения и есть ли у очередей потребители
rabbitmqctl list_queues name messages_ready messages_unacknowledged consumers
# Состояние кластера: кто в строю, кто отвалился
rabbitmq-diagnostics cluster_status
# Проверки для healthcheck в Kubernetes или Docker
rabbitmq-diagnostics check_running
rabbitmq-diagnostics check_port_connectivity
3. HTTP API. Тот же источник, что питает панель, — удобен для скриптов и самописных алертов.
# %2F — это URL-кодированный vhost "/"
curl -u guest:guest http://localhost:15672/api/queues/%2F/orders
4. Prometheus + Grafana. Единственный вариант для продакшена: история, графики, алерты. Плагин отдаёт метрики на порту 15692, официальные дашборды подключаются за десять минут.
rabbitmq-plugins enable rabbitmq_prometheus
# метрики: http://localhost:15692/metrics
Признаки беды
| Симптом | Что произошло | Что делать |
ready растёт линейно, consumers = 0 | Потребители упали или не переподключились после разрыва | Поднять сервис, проверить логику reconnect |
unacked застыл на числе prefetch × потребители | Обработчик завис: вечный запрос без таймаута, дедлок, внешний API не отвечает | Проставить таймауты на все внешние вызовы, перезапустить потребителя |
Высокий redeliver rate | Сообщения ходят по кругу — тот самый poison message | Настроить DLQ и потолок попыток (урок про DLQ) |
| Растёт число соединений и каналов | Приложение открывает соединение на каждое сообщение | Держать одно долгоживущее соединение и канал на поток |
| Издатели вдруг «зависли» на publish | Сработал memory или disk alarm — брокер включил flow control | Смотреть ниже |
Алармы и flow control
У RabbitMQ есть предохранитель. Когда процесс съедает больше vm_memory_high_watermark (по умолчанию 40% оперативной памяти узла) или свободного места на диске остаётся меньше disk_free_limit, брокер поднимает alarm и перестаёт принимать публикации: соединения издателей получают connection.blocked, их basic_publish просто перестаёт возвращать управление.
Со стороны это выглядит как загадочное зависание веб-приложения без единой ошибки в логах. Поэтому запомните связку: «издатели встали намертво, ошибок нет» = смотри алармы брокера. Причина почти всегда одна — очередь, которую никто не разбирал, доросла до потолка памяти. Круг замыкается: именно от этого спасают лимиты и TTL из прошлого урока.
Кластер: зачем и как
Кластер RabbitMQ — это несколько узлов, которые видят друг друга и делят общие метаданные: пользователей, vhost'ы, обменники, определения очередей. Клиент может подключиться к любому узлу и увидеть одну и ту же картину.
И здесь главное недоразумение новичков. Обычная (classic) очередь живёт целиком на одном узле — том, где её создали. Метаданные разошлись по кластеру, а сами сообщения — нет. Падает узел-владелец — очередь становится недоступна вместе со всем содержимым, хотя кластер формально жив. Кластер сам по себе не даёт отказоустойчивости данных.
Даёт её quorum queue — очередь, реплицированная по алгоритму консенсуса Raft. Тип задаётся при объявлении:
ch.queue_declare(
queue='orders',
durable=True,
arguments={
'x-queue-type': 'quorum', # вместо classic
'x-quorum-initial-group-size': 3, # три реплики на трёх узлах
'x-delivery-limit': 5, # 5 неудачных доставок → DLX
'x-dead-letter-exchange': 'orders.dlx',
},
)
Что здесь важно:
- Число узлов — нечётное: 3 или 5. Raft требует большинства (для трёх узлов — двух). Кластер из двух узлов бесполезен: потеря одного — потеря большинства.
x-delivery-limit— та самая четвёртая дверь в DLX. Quorum queue сама считает доставки в заголовкеx-delivery-countи после лимита отправляет сообщение в карантин. Бесконечный цикл переотправки, о котором мы говорили в первом уроке, здесь предотвращён на уровне брокера, без единой строчки кода.- Тип очереди нельзя сменить ни policy, ни повторным объявлением — только пересоздать. Решайте на старте.
- Quorum queues платят за надёжность: они всегда durable, пишут на диск на всех репликах и не поддерживают часть возможностей classic-очередей. Для потока телеметрии, который не жалко, classic-очередь честнее и быстрее.
Как это работает
В quorum queue у каждой очереди есть лидер и последователи. Все операции идут через лидера; сообщение считается принятым, только когда его записало большинство реплик — для группы из трёх это две. Упал лидер — оставшиеся двое выбирают нового, клиенты переподключаются, данные на месте. Упали двое из трёх — большинства нет, очередь замирает и отказывает в записи. Это не баг, а осознанный выбор: лучше отказать, чем разъехаться на две расходящиеся копии.
Отсюда же правило про сетевые разделы (split brain). Если сеть рвётся пополам, RabbitMQ по умолчанию должен решить, кому жить. Рекомендуемая стратегия — pause_minority: узлы, оказавшиеся в меньшинстве, добровольно приостанавливаются и не принимают клиентов, пока связь не восстановится.
cluster_partition_handling = pause_minority
И последнее, о чём молчат туториалы: кластер не растягивают через интернет. Raft чувствителен к задержкам, узлы должны стоять в одном датацентре с быстрой сетью между ними. Для связи между регионами есть отдельные инструменты — плагины Shovel и Federation, которые асинхронно перекачивают сообщения между независимыми брокерами.
Частые ошибки
- Мониторить только размер очереди. Число само по себе ничего не значит — алертить надо на устойчивый рост и на «нет потребителей», а не на абсолютную длину.
- Кластер из двух узлов. Не даёт кворума. Три — минимум, имеющий смысл.
- Считать, что кластер = отказоустойчивость. Classic-очередь на упавшем узле недоступна, кластер здесь ничем не помогает. Нужны quorum queues.
- Игнорировать
unacked. Растущий unacked при пустом ready — это тихо умирающие потребители, которых панель показывает живыми. - Открывать соединение на каждое сообщение. TCP-handshake плюс AMQP-handshake на каждую публикацию: сотни соединений, упёршийся лимит файловых дескрипторов, лежащий брокер.
- Не проверять healthcheck перед выкаткой.
rabbitmq-diagnostics check_runningв контейнере стоит две минуты настройки и экономит часы.
Итоги
- Следите за производной, а не за размером:
publish rateустойчиво вышеack rate— очередь не разгребётся сама никогда. - Застывший
unacked, равныйprefetch × потребители, — верный признак зависшего обработчика. - Панель на 15672 — для разбора инцидента, Prometheus на 15692 — для постоянного наблюдения и алертов.
- Внезапно «зависшие» издатели без ошибок — почти всегда memory или disk alarm и включённый flow control.
- Кластер делит метаданные, но classic-очередь живёт на одном узле; отказоустойчивость данных даёт только quorum queue.
- Quorum queues — нечётное число узлов (3 или 5),
x-delivery-limitвместо самописного счётчика попыток, тип очереди назад не поменять. - Кластер — в пределах датацентра; между регионами — Shovel и Federation.