Ответ
Я использовал RabbitMQ в нескольких проектах на PHP (Symfony/Laravel) для построения асинхронной, отказоустойчивой коммуникации между сервисами.
Основные сценарии:
- Фоновая обработка задач: отправка email, генерация PDF-отчетов, обработка загруженных файлов. Задачи помещались в очередь, а воркеры (обычно Symfony Console-команды или Laravel Queues с драйвером
rabbitmq) обрабатывали их независимо от основного HTTP-запроса. - Событийная архитектура (Event-Driven): при изменении сущности в одном микросервисе (например, «Заказ создан») публиковалось событие в RabbitMQ. Другие сервисы (сервис уведомлений, сервис аналитики) подписывались на это событие и реагировали, не создавая прямых жестких зависимостей.
- Балансировка нагрузки: несколько экземпляров воркеров подписывались на одну очередь, и RabbitMQ распределял сообщения между ними по принципу round-robin.
С чем работал и пример кода (PHP с библиотекой php-amqplib):
// Публикация сообщения с персистентностью
$connection = new AMQPStreamConnection('rabbitmq-host', 5672, 'user', 'pass');
$channel = $connection->channel();
// Объявление очереди (durable=true для сохранения при перезагрузке брокера)
$channel->queue_declare('order_processing', false, true, false, false);
$messageBody = json_encode(['order_id' => 123, 'action' => 'created']);
$msg = new AMQPMessage($messageBody, [
'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT
]);
$channel->basic_publish($msg, '', 'order_processing');
$channel->close();
$connection->close();
Продвинутые практики:
- Dead Letter Exchanges (DLX): Настраивал для перемещения «отравленных» сообщений (которые не удалось обработать после N попыток) в отдельную очередь для анализа.
- TTL (Time-To-Live): Использовал для сообщений с ограниченным сроком актуальности (например, коды подтверждения).
- Подтверждения (Acknowledgements): Всегда включал
$channel->basic_ack()в воркерах после успешной обработки, чтобы избежать потери сообщений. - Кластеризация: На production-окружении разворачивал кластер RabbitMQ (как минимум два узла) с зеркалированием очередей для обеспечения высокой доступности.
Ответ 18+ 🔞
Слушай, я с этой кроличьей фермой, RabbitMQ, на PHP так намаялся, что можно книгу писать. В основном на Symfony и Laravel крутил, когда нужно было, чтобы сервисы между собой болтали, но не синхронно, по-быстрому, а чтоб надёжно и чтобы всё не рухнуло, если один из них вдруг накрылся медным тазом.
Где это говно пригождалось, ёпта:
- Фоновые задачи, которые всех заёбывают: Ну там письма рассылать, отчёты генерировать — овердохуища работы. Вместо того чтобы юзеру полчаса ждать, пока PDF выплюнет, ты просто кидаешь задачу в очередь и говоришь «разбирайтесь». А воркеры на другом конце, как голодные псы, их и хавают. В Laravel это через их Queues делается, только драйвер
rabbitmqставишь, а в Symfony — консольные команды, которые слушают канал. - Архитектура на событиях, чтобы сервисы не знали друг о друге в лицо: Допустим, в сервисе заказов создали новый заказ. Вместо того чтобы тупо дергать API сервиса нотификаций и сервиса аналитики (а если они легли — пиши пропало), мы просто орем в RabbitMQ: «Эй, народ, заказ-то создался!». А кто хочет — тот подписывается и делает что надо. Никаких прямых связей — красота, блядь.
- Балансировка, чтоб не перегрузить одного: Можно запустить десять одинаковых воркеров, подписать их на одну очередь, и кролик сам будет раскидывать сообщения по ним по кругу. Один воркер упал — да похуй, остальные работают. Просто и гениально.
Вот на что руки набил и кусок кода для наглядности (PHP с php-amqplib):
// Отправка сообщения, чтоб оно даже после перезагрузки брокера не потерялось
$connection = new AMQPStreamConnection('rabbitmq-host', 5672, 'user', 'pass');
$channel = $connection->channel();
// Объявляем очередь (durable=true — это чтобы она пережила ребут кролика)
$channel->queue_declare('order_processing', false, true, false, false);
$messageBody = json_encode(['order_id' => 123, 'action' => 'created']);
$msg = new AMQPMessage($messageBody, [
'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT // Вот эта штука — самое важное
]);
$channel->basic_publish($msg, '', 'order_processing');
$channel->close();
$connection->close();
А вот где начинается настоящая магия, когда уже мозг включать надо:
- Dead Letter Exchanges (DLX): Это, блядь, спасение. Если сообщение никак не обрабатывается (воркер его пять раз прочитал и выплюнул), то вместо того чтобы болтаться в очереди вечно, оно летит в специальную «мертвую» очередь. Потом открываешь, смотришь — ага, сообщение-то кривое, данные не те. Без этого — терпения ноль ебать, искать ошибку.
- TTL (Время жизни): Ставишь сообщению срок годности. Идеально для всяких одноразовых кодов подтверждения. Прошло 5 минут — сообщение самоуничтожилось, и воркеру даже не пришло.
- Подтверждения (Acknowledgements): Это святое. Воркер должен явно сказать кролику: «Окей, чувак, я сообщение проглотил и переварил, можешь его удалять». Если не сделать — при перезапуске воркера сообщения потекут рекой обратно, и будет пиздец, дубликаты по всей системе.
- Кластеризация в продакшене: Один кролик — это точка отказа, это пизда рулю. Поэтому ставил кластер из двух-трёх нод с зеркалированием очередей. Одна нода легла — остальные продолжают работать. Без этого на production выходить — это чисто идиотизм, ядрёна вошь.