Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124


З розвитком проєкту, розробники часто стикаються з тим, що сервіс починає “лягати” під навантаженням. Користувачі скаржилися на повільну обробку замовлень, а сервер просто не встигав обробляти всі запити одночасно. Спроба масштабувати додаток виявилася тупиком — поки я не відкрив для себе світ черг повідомлень RabbitMQ для PHP. Це було як відкриття нового виміру в архітектурі додатків.
Сьогодні розповім вам, як RabbitMQ може змінити ваш PHP-проєкт, і що важливіше — як почати працювати з ним без головного болю.
Зміст
ToggleRabbitMQ — це брокер повідомлень (message broker, черги php), який працює як пошта між різними частинами вашого додатку. Уявіть: замість того, щоб виконувати всі задачі синхронно і змушувати користувача чекати, ви просто кладете завдання в чергу, а воркери обробляють їх у фоновому режимі.
Типові сценарії використання RabbitMQ у PHP-додатках:
Переваги RabbitMQ для PHP-проєктів очевидні: швидша відповідь користувачу, краща масштабованість і відмовостійкість. Але є й нюанси, про які варто знати:
Плюси:
Мінуси:
Перш ніж писати код, треба встановити сам RabbitMQ. Найпростіший спосіб для розробки — використати Docker. Створіть файл docker-compose.yml:
version: '3.8'
services:
rabbitmq:
image: rabbitmq:3-management
container_name: rabbitmq
ports:
- "5672:5672" # AMQP порт
- "15672:15672" # Management UI
environment:
RABBITMQ_DEFAULT_USER: admin
RABBITMQ_DEFAULT_PASS: admin
volumes:
- rabbitmq_data:/var/lib/rabbitmq
volumes:
rabbitmq_data:Code language: PHP (php)Запустіть контейнер командою:
docker-compose up -dЧерез кілька секунд RabbitMQ буде доступний. Відкрийте браузер і перейдіть на http://localhost:15672 — це Management UI, де можна моніторити черги. Логін і пароль: admin/admin.


Тепер встановимо PHP-бібліотеку для роботи з RabbitMQ:
composer require php-amqplib/php-amqplibCode language: JavaScript (javascript)Це офіційна бібліотека для роботи з AMQP протоколом (Advanced Message Queuing Protocol), на якому базується RabbitMQ. Документацію можна знайти на GitHub сторінці проєкту.
Producer (виробник) — це код, який створює і відправляє повідомлення в чергу. Створимо простий приклад відправки email-нотифікації:
<?php
// producer.php
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
// Підключаємося до RabbitMQ
$connection = new AMQPStreamConnection(
'localhost', // хост
5672, // порт
'admin', // користувач
'admin' // пароль
);
$channel = $connection->channel();
// Оголошуємо чергу (якщо не існує - створить)
$channel->queue_declare(
'email_queue', // назва черги
false, // passive
true, // durable - черга переживе перезапуск
false, // exclusive
false // auto_delete
);
// Формуємо дані для відправки
$emailData = json_encode([
'to' => 'user@example.com',
'subject' => 'Вітаємо!',
'body' => 'Дякуємо за реєстрацію на нашому сайті',
'timestamp' => time()
]);
// Створюємо повідомлення
$message = new AMQPMessage(
$emailData,
['delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT]
);
// Відправляємо в чергу
$channel->basic_publish($message, '', 'email_queue');
echo " [x] Відправлено email в чергу\n";
// Закриваємо з'єднання
$channel->close();
$connection->close();Code language: PHP (php)Що тут відбувається? Ми підключилися до RabbitMQ, створили чергу з назвою email_queue, сформували JSON із даними листа і відправили його. Параметр durable гарантує, що черга не зникне після перезапуску сервера, а DELIVERY_MODE_PERSISTENT — що саме повідомлення теж збережеться.
Тепер напишемо Consumer (споживача) — воркер, який буде читати повідомлення з черги і обробляти їх:
<?php
// consumer.php
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
$connection = new AMQPStreamConnection(
'localhost', 5672, 'admin', 'admin'
);
$channel = $connection->channel();
// Підключаємося до існуючої черги
$channel->queue_declare(
'email_queue', false, true, false, false
);
echo " [*] Очікуємо повідомлення. Для виходу: CTRL+C\n";
// Callback функція для обробки кожного повідомлення
$callback = function ($msg) {
$data = json_decode($msg->body, true);
echo " [x] Отримано email:\n";
echo " Кому: {$data['to']}\n";
echo " Тема: {$data['subject']}\n";
// Тут ваша логіка відправки email
// mail($data['to'], $data['subject'], $data['body']);
// Імітуємо обробку
sleep(2);
echo " [✓] Email відправлено\n";
// Підтверджуємо обробку повідомлення
$msg->ack();
};
// Налаштування споживача
$channel->basic_qos(
null, // prefetch_size
1, // prefetch_count - обробляти по одному
null // global
);
$channel->basic_consume(
'email_queue', // черга
'', // consumer tag
false, // no_local
false, // no_ack - чекаємо підтвердження
false, // exclusive
false, // nowait
$callback // наша функція
);
// Нескінченний цикл обробки
while ($channel->is_consuming()) {
$channel->wait();
}
$channel->close();
$connection->close();Code language: HTML, XML (xml)Запустіть consumer у терміналі:
php consumer.phpCode language: CSS (css)А в іншому вікні відправте повідомлення:
php producer.phpCode language: CSS (css)Ви побачите, як consumer одразу прийняв і обробив повідомлення. Магія! Параметр prefetch_count: 1 каже RabbitMQ видавати воркеру тільки одне повідомлення за раз. Це важливо для рівномірного розподілу навантаження між кількома воркерами.
У реальному світі не все працює ідеально. API падають, бази тимчасово недоступні, а мережа може глючити. Треба вміти обробляти помилки:
$callback = function ($msg) {
try {
$data = json_decode($msg->body, true);
// Спроба відправити email
$result = sendEmail($data);
if ($result) {
// Успіх - підтверджуємо
$msg->ack();
echo " [✓] Email відправлено успішно\n";
} else {
// Невдача - повертаємо в чергу
$msg->nack(false, true);
echo " [!] Помилка, повідомлення повернуто в чергу\n";
}
} catch (\Exception $e) {
echo " [✗] Критична помилка: {$e->getMessage()}\n";
// Перевіряємо кількість спроб
$headers = $msg->get_properties();
$retryCount = $headers['application_headers']['x-retry-count'] ?? 0;
if ($retryCount < 3) {
// Повертаємо з лічильником спроб
$msg->nack(false, true);
} else {
// Забагато спроб - відправляємо в DLQ
$msg->ack();
// Тут можна записати в dead letter queue
logFailedMessage($data);
}
}
}Code language: PHP (php)Метод ack() (acknowledge) каже RabbitMQ, що повідомлення успішно оброблено і його можна видалити з черги. nack() (negative acknowledge) з параметром requeue: true повертає повідомлення назад у чергу для повторної обробки.
Якщо ви працюєте з фреймворками, є готові інтеграції. У Laravel найпопулярніша бібліотека — vladimir-yuldashev/laravel-queue-rabbitmq. Після встановлення ви можете диспатчити джоби як завжди:
// Laravel Job
dispatch(new SendEmailJob($user));Code language: PHP (php)А Laravel сам покладе це в RabbitMQ чергу. Детальніше про rabbitmq Laravel queues читайте в нашому гайді по Laravel Queue.
У Symfony використовується компонент Messenger, який також підтримує RabbitMQ з коробки. Налаштування виглядає так:
# config/packages/messenger.yaml
framework:
messenger:
transports:
async: '%env(MESSENGER_TRANSPORT_DSN)%'
routing:
'App\Message\EmailNotification': asyncCode language: PHP (php)Більше про асинхронну обробку в PHP можна дізнатись у статті про асинхронне програмування на PHP.
Management UI — це чудово, але для продакшену потрібен серйозніший моніторинг. RabbitMQ експортує метрики у форматі Prometheus, які можна візуалізувати в Grafana. Також рекомендую звернути увагу на:
Корисні команди для дебагу:
# Список черг
rabbitmqctl list_queues
# Детальна інформація про чергу
rabbitmqctl list_queues name messages_ready messages_unacknowledged
# Список з'єднань
rabbitmqctl list_connections
# Очистити чергу (обережно!)
rabbitmqctl purge_queue email_queueCode language: PHP (php)За роки роботи з RabbitMQ для PHP я зібрав список must-have налаштувань для продакшену:
Приклад конфігурації Supervisor:
[program:rabbitmq-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /path/to/consumer.php
autostart=true
autorestart=true
numprocs=3
user=www-data
redirect_stderr=true
stdout_logfile=/var/log/rabbitmq-worker.logCode language: JavaScript (javascript)Детальніше про налаштування production оточення читайте у гайді по deployment Laravel PHP додатків.
RabbitMQ для PHP— це потужний інструмент, який може радикально змінити архітектуру вашого PHP-додатку. Так, він додає складності, але переваги з лишком перекривають витрати. Швидкість відповіді користувачам, можливість масштабування і відмовостійкість — це те, чого не досягнути синхронною обробкою.
Починайте з простих сценаріїв: відправка email, генерація PDF, обробка зображень. Коли освоїте базові концепції, можна переходити до складніших патернів — exchanges, routing keys, RPC через RabbitMQ.
Офіційну документацію RabbitMQ ви знайдете на rabbitmq.com, а туторіали для PHP — в розділі Getting Started.



