До основного вмісту

Swoole і RoadRunner: PHP як довгоживучий процес

PHP · 29.09.2026

Класичний PHP-FPM запускає інтерпретатор заново на кожен запит: підняв застосунок, обробив один запит, вивантажив усе з пам'яті. Swoole і RoadRunner працюють інакше — застосунок завантажується один раз і тримається в пам'яті між запитами, як у Node.js або Go. Це пришвидшує обробку в рази, але вимагає іншого підходу до коду.

Чим це відрізняється від звичного PHP-FPM

У моделі FPM кожен запит отримує чистий стан: жодних витоків між користувачами, але щоразу заново ініціалізується контейнер залежностей, з'єднання з базою і автозавантаження класів. У моделі Swoole або RoadRunner ініціалізація відбувається один раз при старті воркера, а далі на кожен запит виконується лише код обробника — це і дає основний приріст швидкості. Різницю зі звичайним CLI-запуском PHP розбирали у статті про PHP CLI і FPM.

Зворотний бік — глобальний стан. Статичні властивості класів, синглтони і просто забуті змінні в замиканнях живуть між запитами і можуть текти в пам'ять або протікати даними одного користувача до іншого, якщо код не написаний із розрахунком на довгий процес.

Встановлення Swoole як розширення PHP

sudo apt install php8.3-dev php-pear
sudo pecl install swoole
echo "extension=swoole.so" | sudo tee /etc/php/8.3/mods-available/swoole.ini
sudo phpenmod swoole
php -m | grep swoole

Swoole вбудовується прямо в PHP як розширення і додає класи для асинхронного HTTP-сервера, корутин і вебсокетів. Про окремий протокол вебсокетів на чистому PHP — у статті про WebSockets із Ratchet.

RoadRunner як альтернатива

RoadRunner влаштований інакше: це окремий бінарник на Go, який тримає пул PHP-воркерів і спілкується з ними за протоколом Goridge через stdin/stdout. PHP-код при цьому лишається звичайним PHP без спеціального розширення — потрібен лише пакет spiral/roadrunner-http через Composer, який описано у статті про встановлення Composer.

ПараметрSwooleRoadRunner
Типрозширення PHPокремий бінарник на Go
Корутинитак, вбудованіні, воркери однопотокові
Сумісність з Laravel/Symfonyчерез окремі пакетичерез окремі пакети
Поріг входувищийнижчий

На що дивитись при витоках пам'яті

Довгоживучий процес робить витоки помітними за хвилини, а не за тижні, як у звичайних десктопних застосунках. Перевірте ці місця:

  • Статичні масиви і кеші рівня класу, які ростуть з кожним запитом і ніколи не очищаються.
  • З'єднання з базою даних, яке переідкривається на кожен запит замість повторного використання вже відкритого з'єднання.
  • Глобальний контейнер залежностей — якщо він створюється заново на кожен запит, то втрачається весь сенс довгоживучого процесу.
  • Циклічні посилання між об'єктами, які збирач сміття PHP не завжди прибирає вчасно у довгому процесі.

Моніторинг воркерів і перезапуск

Навіть правильно написаний застосунок варто перезапускати за розкладом, так само як і звичайні черги — підхід майже такий самий, як у статті про Supervisor для черг. У Swoole є вбудований параметр max_request, який перезапускає воркер після заданої кількості оброблених запитів:

$server->set([
    'worker_num' => 4,
    'max_request' => 5000,
    'task_worker_num' => 2,
]);

Чек-лист переходу на довгоживучий процес

  1. Приберіть із коду будь-які статичні властивості, які накопичують дані між запитами без явного очищення.
  2. Налаштуйте плановий перезапуск воркерів через max_request у Swoole або аналогічний ліміт у RoadRunner.
  3. Прожене навантажувальне тестування перед перемиканням проду — зростання затримок за час роботи воркера одразу покаже витік.
← Назад до бази знань Поставити питання підтримці