Зачем RabbitMQ «тормозит»: это самозащита, а не поломка
Когда в RabbitMQ что-то идёт не так, симптомы обычно похожи: растут очереди, продюсеры жалуются на задержки, в логах встречаются flow control, memory watermark, disk alarm, а в приложении всплывает blocked connection. Важно понимать: чаще всего это не «внезапный баг», а предсказуемая реакция на перегруз.
Задача брокера — не «держать максимальный TPS любой ценой», а не умереть от OOM и не забить диск. Поэтому RabbitMQ умеет:
- включать flow control (backpressure) и замедлять приём публикаций от продюсеров;
- поднимать memory watermark (порог по RAM), после которого включаются ограничения;
- поднимать disk alarm (порог по свободному месту), чтобы не угробить ноду;
- временно блокировать публикации по соединению — то самое blocked connection.
Цель админа/DevOps — не отключать защиту, а привести систему в режим, где она почти не срабатывает, а если и срабатывает — то кратко и предсказуемо.
Быстрый словарь терминов: о чём говорят логи и графики
Flow control
Flow control — набор механизмов, которыми RabbitMQ ограничивает входящий поток публикаций (и частично внутреннюю обработку), когда видит риск по ресурсам. Это backpressure: брокер говорит клиенту «подожди».
Memory watermark
Memory watermark — порог использования RAM, после которого RabbitMQ начинает ограничивать скорость (в том числе через блокировку публикаций). Управляется параметром vm_memory_high_watermark (обычно доля от доступной памяти).
Disk alarm
Disk alarm — сигнал о том, что на диске осталось слишком мало места. В этом состоянии RabbitMQ будет агрессивно ограничивать приём данных, чтобы не довести узел до отказа.
Consumer lag
Consumer lag — накопленное отставание потребителей: сообщения публикуются быстрее, чем обрабатываются. На очереди это проявляется ростом Ready и/или Unacked, увеличением «возраста» сообщений и падением фактической скорости подтверждений.
Blocked connection
Blocked connection — состояние соединения, когда брокер временно запрещает публикации (обычно из-за memory watermark или disk alarm). Клиент остаётся подключённым, но publish-операции начинают ждать.
Publisher confirms, channels и prefetch
Publisher confirms — подтверждения от брокера, что публикация принята и обработана на стороне RabbitMQ (в рамках выбранной модели надёжности). Это ключевой инструмент для управляемого backpressure.
Один TCP-коннект может содержать несколько channels (AMQP-каналов). На стороне потребителя ключевой параметр — prefetch (QoS): сколько сообщений брокер может выдать «в долг» без ack.

Как быстро понять: сработал memory watermark или disk alarm
Начинайте с фактов на стороне RabbitMQ, а не с догадок приложения.
Management UI и базовая проверка через CLI
В management UI обычно сразу видно:
- потребление памяти и флаги Memory alarm;
- свободное место и Disk alarm;
- rates: publish/deliver/ack;
- по очередям: Ready, Unacked, скорость, число consumers;
- по соединениям: состояние блокировки (если включён connection blocking).
Если UI нет под рукой, используйте CLI на ноде RabbitMQ:
rabbitmq-diagnostics status
rabbitmq-diagnostics memory_breakdown
rabbitmqctl list_queues name messages_ready messages_unacknowledged consumers state
rabbitmqctl list_connections name state channels client_properties
В выводе rabbitmq-diagnostics status смотрите раздел alarms: наличие memory/disk alarms почти всегда объясняет blocked connection на продюсерах.
Классическая картина при consumer lag: Ready vs Unacked
- Растёт messages_ready: потребители не успевают за входящим потоком, их мало или они не подключены.
- Растёт messages_unacknowledged: сообщения выданы consumers, но они долго их обрабатывают и не возвращают
ack.
Второй сценарий часто связан с завышенным prefetch или деградацией downstream-зависимостей (БД, внешний API, блокировки, GC-паузы, нехватка CPU).
Почему срабатывает memory watermark: частые причины в проде
Memory watermark почти всегда включается из-за сочетания факторов. Ниже — то, что реально встречается чаще всего.
1) Слишком много Unacked из-за prefetch
Если prefetch велик (или библиотека выставила его агрессивно), брокер может «залить» одному consumer тысячи сообщений. Они станут Unacked, займут память (метаданные, индексы, ссылки на payload), и при больших объёмах это быстро приближает ноду к watermark.
Практика: начинайте с небольшого prefetch (например, 10–200 в зависимости от времени обработки и размера сообщений) и увеличивайте только по измерениям.
2) Большие сообщения и/или крупные батчи публикаций
Большой payload увеличивает давление на память и диск, а при торможении потребителей очередь быстрее «толстеет». Если по бизнес-логике нужны большие объекты, часто разумнее хранить payload отдельно (объектное хранилище/БД), а в RabbitMQ передавать ссылку и метаданные.
Если у вас подобные паттерны с объектным хранилищем, полезно держать в голове нюансы консистентности и кеширования на CDN; в отдельных сценариях пригодится материал про паттерны работы с eventual consistency в S3-подобных хранилищах.
3) Много соединений и каналов
Каждое соединение и канал дают накладные расходы. Архитектура «каждый воркер открывает своё соединение и десятки каналов» может неожиданно съесть RAM. Обычно лучше меньше соединений, но достаточно каналов для параллелизма, плюс обязательное управление потоком публикаций на клиенте.
4) Приоритеты, множество очередей, policies и сложная маршрутизация
Много очередей, сложные bindings и приоритетные очереди увеличивают метаданные и внутренние структуры. Это нормально, но требует аккуратного sizing.
Disk alarm: когда проблема не в RAM
Disk alarm важно не путать с «диск медленный». На практике это два разных класса проблем:
- мало свободного места: RabbitMQ включает disk alarm и ограничивает приём публикаций;
- высокая задержка I/O: места может быть достаточно, но fsync и общая нагрузка делают публикации и confirms медленными.
Базовая проверка места, inode и задержек диска:
df -h
df -i
iostat -xz 1
Если disk alarm включается регулярно, обычно это означает: вы недооценили время хранения (lag копит сообщения), раздел под данные слишком мал, или место «съедают» логи/дампы. Это решается архитектурой и планированием ресурсов, а не отключением защиты.
Blocked connection: что происходит на стороне продюсера
Когда RabbitMQ блокирует соединение, приложение обычно видит одно из трёх:
- publish начинает занимать секунды/минуты (вызов ждёт);
- включается клиентский таймаут и вы получаете ошибки;
- растёт буфер на стороне клиента (in-memory), затем упираетесь в RAM уже в приложении.
Ключевой момент: blocked connection — это сигнал «замедляйся». Если клиент продолжит «лить» без ограничений, получится лавина: брокер блокирует, клиент буферизует, клиент падает по памяти, рестартуется и пытается «догнать», делая ещё хуже.
Как правильно переживать блокировки: confirms и лимит in-flight
На продюсере включайте publisher confirms и ограничивайте число неподтверждённых сообщений (in-flight). Тогда при перегрузе подтверждения приходят медленнее, и продюсер автоматически снижает throughput.
Отдельно проверьте потокобезопасность клиента: у многих библиотек практическое правило — «один канал на поток» (или аккуратный пул каналов). Публикация из десятков потоков в один channel без синхронизации может давать задержки, гонки и неожиданные таймауты.
Consumer lag: пошаговая диагностика «почему очередь растёт»
Ниже — чек-лист, который в проде помогает быстро локализовать узкое место.
Шаг 1. Разделите проблему на «publish быстрее» или «consume медленнее»
Смотрите rates (publish/deliver/ack). Если publish стабильно выше ack, lag будет накапливаться. Важно понять: это постоянный дисбаланс (нужно масштабирование/оптимизация), или кратковременный пик (нужны буферы и лимиты).
Шаг 2. Посмотрите Ready vs Unacked
- Ready растёт: потребителей мало, они не подключены или их throughput недостаточный. Проверяйте количество consumers, ошибки подключения, рестарты, конкуренцию за очередь.
- Unacked растёт: потребители получили сообщения, но долго не ack’ают. Частые причины: долгие транзакции, внешний API, блокировки, слишком большой
prefetch, зависшие воркеры.
Шаг 3. Проверка prefetch и времени обработки
Поставьте предсказуемый prefetch и измерьте среднее время обработки сообщения. Прикидка по параллелизму:
consumers ≈ incoming_rate * avg_processing_time
Пример: 500 msg/s и обработка 50 ms (0.05 s) дают около 25 параллельных обработчиков, чтобы удерживать очередь без роста (без учёта накладных расходов и всплесков).
Шаг 4. Ищите «ядовитые» сообщения и head-of-line blocking
Одна-две тяжёлые задачи могут удерживать ack и создавать иллюзию общей деградации. Если consumer один и prefetch большой, тяжёлые сообщения дают head-of-line blocking. Типовые решения: увеличить параллелизм, разделить очереди по типам задач, внедрить retry/DLQ-паттерны.
Шаг 5. Проверьте сетевую стабильность кластера: net_ticktime
net_ticktime относится к взаимодействию Erlang-нод и влияет на то, как быстро обнаруживаются «подвисшие» узлы по сети. Слишком маленькое значение в нестабильной сети может приводить к ложным разрывам и каскадным проблемам. Слишком большое — замедляет обнаружение реальных проблем.
На одиночной ноде RabbitMQ
net_ticktimeобычно не является первопричиной consumer lag, но в кластере этот параметр заметно влияет на устойчивость при сетевых «микро-обрывах».

Практические настройки: что трогать безопасно, а что не крутить «наугад»
Prefetch (QoS) на потребителях
Это самый частый и обычно самый безопасный рычаг:
- если обработка тяжёлая и медленная — уменьшайте
prefetch; - если обработка очень быстрая, а RTT заметный — увеличивайте
prefetchумеренно; - если consumers часто рестартуют — избегайте огромного
prefetch, иначе Unacked будут «прыгать» при переподключениях.
Publisher confirms на продюсерах
Включайте confirms и ограничивайте число in-flight. Дополнительно используйте ретраи с джиттером и лимитами, чтобы не «раскачивать» брокер после восстановления.
Channels: отделяйте параллелизм от потокобезопасности
Частая здоровая модель: один connection на процесс/под (или несколько по необходимости), каналы — пулом под параллелизм, но без тысяч соединений «на всякий случай».
Memory watermark: когда имеет смысл менять
Поднимать vm_memory_high_watermark стоит только если вы понимаете профиль нагрузки и уверены, что системе хватает RAM. Слишком высокий watermark увеличивает риск OOM и «жёсткой смерти» ноды, что почти всегда хуже, чем временная блокировка публикаций.
Ориентир фрагмента конфигурации:
# rabbitmq.conf
vm_memory_high_watermark.relative = 0.6
Disk free limit и отдельный раздел под данные
Смысл простой: оставить запас, чтобы RabbitMQ и ОС могли жить и обслуживать собственные операции. Проверьте, что data-dir RabbitMQ расположен на предсказуемом томе и что места достаточно под пики и хвосты после лагов.
Типовые сценарии «сломалось» и быстрые действия
Сценарий A: очередь растёт, memory watermark, blocked connection
- Ограничьте входящий поток: confirms + лимит in-flight на стороне продюсеров, временно снизьте скорость публикаций.
- Уменьшите
prefetchи убедитесь, что consumers реально возвращаютack. - Проверьте объём Unacked: если он огромный, проблема чаще в потребителях и их параллелизме.
- Оцените размер сообщений и наличие «тяжёлых» задач.
Сценарий B: disk alarm, публикации встают
- Срочно освободите место: логи, дампы, старые файлы, забытые артефакты деплоя.
- Разберите причину накопления сообщений: потребители умерли или недомасштабированы.
- Проверьте I/O: возможно, том перегружен соседями или просто не подходит по классу для текущей нагрузки.
Сценарий C: consumer lag без alarms, но задержки растут
- Проверьте downstream-зависимости consumers (БД/API), время обработки и блокировки.
- Убедитесь, что масштабирование consumers действительно увеличивает throughput (часто упираются в одну БД).
- Контролируйте thundering herd: слишком много consumers может «положить» внешний ресурс.
Набор метрик, без которых диагностика превращается в гадание
Чтобы ловить проблемы до жалоб пользователей, закрепите минимум наблюдаемости:
- RabbitMQ: publish/deliver/ack rates, memory/disk alarms, глубина очередей (Ready/Unacked), число consumers, churn подключений;
- consumers: время обработки, процент ошибок, ретраи, таймауты внешних сервисов;
- ОС/виртуализация: load, iowait, latency диска, сетевые потери, CPU steal (если актуально);
- продюсер: размер буфера, число in-flight, время ожидания confirms.
Если часть consumers у вас на PHP-FPM, полезно уметь быстро отделять «RabbitMQ тормозит» от «воркеры упираются в PHP». В этом помогает разбор как читать PHP-FPM slowlog и находить узкие места.
Когда проблема не лечится настройками: sizing и архитектура
Иногда flow control и consumer lag — сигнал, что нагрузка выросла за пределы выбранных ресурсов. Если брокер регулярно упирается в watermark или диск, а consumers стабильно отстают при нормальных настройках, обычно остаются два направления:
- масштабировать обработку: больше consumers, оптимизация бизнес-логики, разгрузка БД/кэши;
- масштабировать инфраструктуру RabbitMQ: больше RAM/CPU, быстрый диск, выделение брокера на отдельный узел, пересмотр топологии (разделение очередей по сервисам/типам задач).
В проде RabbitMQ чувствителен к качеству диска и предсказуемости CPU. Для стабильного throughput обычно полезнее отдельная VM/сервер с понятными лимитами и мониторингом. Если вы размещаете брокер в облаке, логичнее выделять под него VDS с гарантированными ресурсами, чем делить диск и CPU с шумными соседями.
Итоги: как связаны flow control, watermark и lag
- consumer lag накапливает сообщения (Ready/Unacked);
- накопление увеличивает давление на память и диск;
- при достижении порогов включаются memory watermark и/или disk alarm;
- брокер активирует flow control, и продюсеры видят blocked connection и рост задержек;
- publisher confirms, корректные channels и разумный prefetch делают это поведение управляемым и предсказуемым.
Если хотите, можно разобрать конкретный кейс по вашим метрикам: значения Ready/Unacked, rates, alarms, размер сообщений, prefetch, число consumers и параметры confirms/in-flight.


