RabbitMQ
RabbitMQ — open-source брокер сообщений на Erlang с протоколом AMQP: брокер сам маршрутизирует сообщения по очередям и удаляет их после подтверждения.
Что такое RabbitMQ
RabbitMQ — open-source брокер сообщений: принимает сообщения от приложений, раскладывает их по очередям согласно правилам маршрутизации и отдаёт консьюмерам. Написан на Erlang/OTP, основной протокол — AMQP 0-9-1, через плагины поддерживает MQTT, STOMP и WebSocket.
Два свойства определяют, для чего он годится. Первое: маршрутизацию решает брокер, а не читатель — в отличие от Kafka, где консьюмер сам выбирает, что читать. Второе: сообщение исчезает из очереди после подтверждения. Это очередь задач, а не журнал событий: перечитать вчерашний день нельзя, зато можно гибко решать, кому какое сообщение достанется.
Как устроена маршрутизация
Producer ──► Exchange ──(binding: routing key)──► Queue ──► Consumer
│
└──(другой binding)───────────► Queue ──► Consumer
Продюсер никогда не пишет в очередь напрямую. Он публикует в exchange с routing key, а exchange по своим binding'ам решает, в какие очереди положить копии. Очередей может оказаться ноль (тогда сообщение просто исчезнет), одна или десять.
| Тип exchange | Правило | Когда применяют |
|---|---|---|
direct |
routing key точно совпал с binding key | Задачи по типу: pdf, email, sms |
fanout |
копия во все привязанные очереди | Широковещательные события |
topic |
совпадение по шаблону | Подписка на классы событий |
headers |
по заголовкам, а не по ключу | Редко, когда ключа не хватает |
В topic exchange routing key — слова через точку (logs.error.payments), а в шаблоне * заменяет ровно одно слово, # — ноль или больше: logs.# поймает всё из logs, *.error.* — ошибки любого сервиса.
Подтверждения и prefetch
Сообщение удаляется не в момент отдачи консьюмеру, а когда тот пришлёт ack:
def handle(ch, method, properties, body):
try:
process(body)
ch.basic_ack(method.delivery_tag) # обработали — удалить
except Exception:
ch.basic_nack(method.delivery_tag, requeue=False) # в DLQ, не по кругу
channel.basic_qos(prefetch_count=10) # не больше 10 неподтверждённых на консьюмера
channel.basic_consume("tasks", handle)
Три ошибки, на которых спотыкаются чаще всего:
auto_ack=True— сообщение считается доставленным сразу при отправке. Упал воркер посреди обработки — задача потеряна безвозвратно.- prefetch без ограничения — один быстрый консьюмер загребает всю очередь себе в буфер, остальные простаивают, память брокера растёт. Для долгих задач ставят
prefetch_count=1, для коротких — десятки. requeue=Trueна битом сообщении — оно вернётся в очередь, снова уронит консьюмера и так по кругу. Такие сообщения отправляют в dead letter exchange.
Долговечность, DLQ и кластер
Пережить рестарт брокера сообщение может, только если выполнены оба условия сразу: очередь объявлена durable=true и сообщение опубликовано как persistent (delivery_mode=2). Одного из двух недостаточно — это классический источник «пропавших» задач. Остальное задаётся аргументами очереди:
rabbitmqadmin declare queue name=tasks durable=true \
arguments='{"x-message-ttl":60000,
"x-max-length":100000,
"x-dead-letter-exchange":"dlx"}'
Сообщение живёт 60 секунд и уходит в DLX, длина очереди ограничена, а всё отвергнутое, просроченное и вытесненное попадает в dead letter exchange. DLQ стоит заводить сразу: без неё первое же битое сообщение остановит обработку.
Для отказоустойчивости используют quorum queues: они основаны на алгоритме консенсуса Raft, реплицируются на несколько узлов кластера и переживают потерю меньшинства реплик. Устаревшие классические зеркалируемые очереди в новых проектах не берут. Отдельный тип — streams: append-only лог с неразрушающим чтением, если нужна кафкаподобная семантика, не выходя из RabbitMQ.
Запуск и эксплуатация
docker run -d --name rabbit -p 5672:5672 -p 15672:15672 \
-e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=secret \
rabbitmq:management
# 5672 — AMQP, 5671 — AMQP поверх TLS, 15672 — веб-панель management-плагина
rabbitmqctl list_queues name messages consumers # где копится и кто читает
Наружу открывают только необходимое: панель управления на 15672 в интернете — частая находка сканеров, см. сетевые порты и TLS.
Важная особенность эксплуатации: при достижении memory watermark (по умолчанию около 40% RAM узла) RabbitMQ применяет back-pressure и блокирует продюсеров. Формально это защита, на практике выглядит как «приложение зависло на publish». Причина почти всегда одна — очередь растёт, потому что консьюмеры не справляются.
Когда RabbitMQ — правильный выбор
- Да: раздача задач воркерам (Celery в Python, Spring AMQP в Java), сложные правила маршрутизации, приоритеты, отложенный повтор, RPC поверх очередей, разные SLA у разных типов задач.
- Нет: сотни тысяч событий в секунду, хранение потока на недели, повторное проигрывание истории, поставка данных в аналитику. Это территория Kafka. Если же нужна просто быстрая шина между сервисами без тяжёлой эксплуатации — стоит посмотреть на NATS.
Связанные термины
- Брокеры сообщений — класс систем и общая терминология
- Apache Kafka — брокер с противоположной моделью: лог вместо очереди
- NATS — более лёгкая альтернатива для внутренней шины
- Микросервисы и монолит — где обычно и появляется RabbitMQ
- Docker Compose — обычный способ поднять RabbitMQ рядом с приложением
Готовы запустить GPU-задачу?
Запустить GPU-сервер