Если ваш сайт когда-нибудь «зависал» из-за отправки писем или генерации отчётов, вы знаете, как важно разгрузить основной поток. RabbitMQ — это брокер сообщений, который помогает делать тяжёлые задачи асинхронно. В статье разберём, как подключить RabbitMQ к PHP-проекту, отправить первое сообщение и не наступить на грабли.
Зачем PHP-разработчику RabbitMQ
Представьте: пользователь нажимает «Заказать», а сайт должен отправить письмо, сгенерировать PDF-счёт и обновить склад. Если делать всё сразу, страница будет грузиться вечность. RabbitMQ решает проблему: PHP-скрипт быстро кладёт задачу в очередь и отвечает пользователю, а отдельный процесс-воркер спокойно разгребает задачи.
RabbitMQ — это не просто «очередь». Это полноценный брокер с обменниками (exchanges), очередями (queues) и привязками (bindings). Он умеет маршрутизировать сообщения по правилам, гарантировать доставку и даже хранить сообщения на диске, если что-то упадёт.
В PHP для работы с RabbitMQ есть библиотека php-amqplib. Она предоставляет удобный API и не требует установки нативных расширений (хотя есть и расширение amqp, но мы возьмём более популярный вариант).
Установка и первое подключение
Сначала установите RabbitMQ. Проще всего через Docker:
docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management
Порт 5672 — для AMQP, 15672 — для веб-интерфейса (логин/пароль: guest/guest).
Теперь установим PHP-библиотеку через Composer:
composer require php-amqplib/php-amqplib
Создадим файл send.php, который отправит сообщение в очередь:
<?php
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
// Подключаемся к RabbitMQ
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
// Объявляем очередь (если её нет, она создастся)
$channel->queue_declare('email_queue', false, false, false, false);
// Формируем сообщение
$data = json_encode(['email' => 'user@example.com', 'subject' => 'Привет']);
$msg = new AMQPMessage($data, ['delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT]);
// Публикуем в очередь
$channel->basic_publish($msg, '', 'email_queue');
echo "Сообщение отправлено\n";
// Закрываем соединение
$channel->close();
$connection->close();
Запустите скрипт — в веб-интерфейсе RabbitMQ (http://localhost:15672) увидите новую очередь с одним сообщением.
Как принимать сообщения: воркер на PHP
Теперь напишем скрипт-потребитель (worker.php), который будет забирать сообщения из очереди и обрабатывать их. Обычно такой скрипт запускают как демон или через supervisor.
<?php
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
$channel->queue_declare('email_queue', false, false, false, false);
echo " [*] Ожидание сообщений. Для выхода нажмите CTRL+C\n";
$callback = function ($msg) {
$data = json_decode($msg->body, true);
echo "Получено: " . print_r($data, true) . "\n";
// Здесь можно отправить письмо, сгенерировать PDF и т.д.
// Подтверждаем обработку
$msg->ack();
};
$channel->basic_consume('email_queue', '', false, false, false, false, $callback);
while ($channel->is_open()) {
$channel->wait();
}
$channel->close();
$connection->close();
Запустите воркер в терминале: php worker.php. Он будет висеть и ждать сообщений. Как только вы запустите send.php, воркер выведет данные и подтвердит обработку.
$msg->ack()) только после успешного выполнения задачи. Если воркер упадёт до подтверждения, RabbitMQ вернёт сообщение в очередь и его получит другой воркер. Это гарантирует, что задача не потеряется.
Обменники и маршрутизация: не только очереди
В примерах выше мы публиковали сообщение напрямую в очередь (используя пустой обменник). Но RabbitMQ славится гибкой маршрутизацией через обменники (exchanges). Самые популярные типы:
- direct — сообщение попадает в очередь с точным совпадением ключа маршрутизации.
- fanout — рассылка во все привязанные очереди (как broadcast).
- topic — маршрутизация по шаблону (например,
user.*). - headers — по заголовкам сообщения (реже используется).
Пример с обменником типа fanout: отправитель публикует сообщение в обменник, а его копии попадают во все очереди, привязанные к этому обменнику.
// Создаём обменник
$channel->exchange_declare('logs', 'fanout', false, false, false);
// Публикуем в обменник (ключ маршрутизации пустой)
$channel->basic_publish($msg, 'logs', '');
Потребители должны заранее создать свои очереди и привязать их к обменнику:
$channel->queue_declare('log_queue_1', false, false, false, false);
$channel->queue_bind('log_queue_1', 'logs', '');
Обработка ошибок и повторные попытки
В реальной жизни воркеры падают, сеть моргает, а сообщения бывают «битыми». Чтобы не потерять данные, используйте механизм подтверждений (ack) и настройку basic_qos для ограничения количества неподтверждённых сообщений на воркер.
Если сообщение не удалось обработать (например, некорректный JSON), его можно отклонить (basic_nack) с параметром requeue=false, чтобы оно не крутилось в очереди бесконечно. Такие сообщения обычно отправляют в «очередь мёртвых писем» (dead letter queue).
Пример настройки очереди с DLX (Dead Letter Exchange):
$args = new \PhpAmqpLib\Wire\AMQPTable([
'x-dead-letter-exchange' => 'dlx_exchange',
]);
$channel->queue_declare('main_queue', false, false, false, false, false, $args);
Теперь, если сообщение будет отклонено или истечёт его TTL, оно автоматически попадёт в обменник dlx_exchange, откуда его можно перенаправить в отдельную очередь для разбора.
rabbitmq_management (он уже включён в Docker-образ с тегом management). Через веб-интерфейс удобно смотреть очереди, отправлять тестовые сообщения и наблюдать за графиками. А для продакшена настройте мониторинг через Prometheus или Zabbix.
Сравнение способов работы с RabbitMQ в PHP
Выбор библиотеки или расширения зависит от нагрузки и требований. Вот краткая таблица:
| Инструмент | Плюсы | Минусы |
|---|---|---|
| php-amqplib | Чистый PHP, легко ставить, гибкий API | Медленнее нативного расширения, требует больше памяти |
| ext-amqp | Высокая производительность, низкое потребление памяти | Требует установки PECL-расширения, меньше примеров |
| Gearman (альтернатива) | Проще в настройке для простых задач | Нет такой гибкой маршрутизации, меньше возможностей |
Для большинства проектов на PHP стартовать с php-amqplib — правильное решение. Если упрётесь в производительность, можно перейти на расширение amqp.
Что в итоге
RabbitMQ — мощный инструмент для асинхронной обработки задач в PHP. Он помогает разгрузить сайт, сделать систему отказоустойчивой и легко масштабировать воркеры. Главное — не забывайте про подтверждения (ack), настройку dead letter exchange и мониторинг. Начните с простого примера из статьи, а затем постепенно усложняйте архитектуру.
Если вы только знакомитесь с очередями, попробуйте для начала вынести отправку писем в отдельный воркер. Это сразу даст ощутимый прирост скорости ответа сайта.

