# Swoole и RoadRunner: PHP как долгоживущий процесс

> Swoole и RoadRunner: чем долгоживущий PHP-процесс отличается от FPM, как настроить сервер и на что смотреть при утечках памяти.

Классический PHP-FPM запускает интерпретатор заново на каждый запрос: поднял приложение, обработал один запрос, выгрузил всё из памяти. Swoole и RoadRunner работают иначе — приложение загружается один раз и держится в памяти между запросами, как в Node.js или Go. Это ускоряет обработку в разы, но требует другого подхода к коду.

## Чем это отличается от привычного PHP-FPM

В модели FPM каждый запрос получает чистое состояние: никаких утечек между пользователями, но каждый раз заново инициализируется контейнер зависимостей, подключение к базе и автозагрузка классов. В модели Swoole или RoadRunner инициализация происходит один раз при старте воркера, а дальше на каждый запрос выполняется только код обработчика — это и даёт основной прирост скорости. Разницу с обычным CLI-запуском PHP разбирали в статье [про PHP CLI и FPM](https://www.zevshost.net/ru/kb/php-cli-vs-fpm-cron/).

Обратная сторона — глобальное состояние. Статические свойства классов, синглтоны и просто забытые переменные в замыканиях живут между запросами и могут утекать в память или протекать данными одного пользователя к другому, если код не написан с расчётом на долгий процесс.

## Установка 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](https://www.zevshost.net/ru/kb/php-websockets-ratchet/).

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

RoadRunner устроен иначе: это отдельный бинарник на Go, который держит пул PHP-воркеров и общается с ними по протоколу Goridge через stdin/stdout. PHP-код при этом остаётся обычным PHP без специального расширения — нужен только пакет `spiral/roadrunner-http` через Composer, который описан в статье [про установку Composer](https://www.zevshost.net/ru/kb/composer-ustanovka-nastroika/).

| Параметр | Swoole | RoadRunner |
| --- | --- | --- |
| Тип | расширение PHP | отдельный бинарник на Go |
| Корутины | да, встроены | нет, воркеры однопоточные |
| Совместимость с Laravel/Symfony | через отдельные пакеты | через отдельные пакеты |
| Порог входа | выше | ниже |

## На что смотреть при утечках памяти

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

- Статические массивы и кэши уровня класса, которые растут с каждым запросом и никогда не очищаются.
- Подключение к базе данных, которое переоткрывается на каждый запрос вместо переиспользования уже открытого соединения.
- Глобальный контейнер зависимостей — если он создаётся заново на каждый запрос, то теряется весь смысл долгоживущего процесса.
- Циклические ссылки между объектами, которые сборщик мусора PHP не всегда убирает вовремя в длинном процессе.

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

Даже правильно написанное приложение стоит перезапускать по расписанию, как и обычные очереди — подход почти такой же, как в статье [про Supervisor для очередей](https://www.zevshost.net/ru/kb/php-ocheredi-supervisor/). У Swoole есть встроенный параметр `max_request`, который перезапускает воркер после заданного числа обработанных запросов:

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

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

1. Уберите из кода любые статические свойства, которые накапливают данные между запросами без явной очистки.
2. Настройте плановый перезапуск воркеров через `max_request` в Swoole или аналогичный лимит в RoadRunner.
3. Прогоните нагрузочное тестирование перед переключением прода — рост задержек по времени работы воркера сразу покажет утечку.

---

Источник: https://www.zevshost.net/ru/kb/php-swoole-roadrunner/
