Перейти к основному содержимому

RoadRunner: высокопроизводительный PHP

RoadRunner — это высокопроизводительный сервер приложений PHP, балансировщик нагрузки и менеджер процессов, написанный на Go. Он работает как постоянный процесс, управляющий пулом PHP-воркеров, устраняя накладные расходы на инициализацию PHP-движка и фреймворка приложения при каждом запросе.

Базовая архитектура​

Протокол Goridge​

RoadRunner использует высокопроизводительный бинарный протокол Goridge для взаимодействия между Go-сервером и PHP-воркерами. Goridge поддерживает различные каналы связи:

  • Pipes (стандартный): быстрый, не требует дополнительной настройки.
  • TCP Sockets: позволяет PHP-воркерам работать на разных машинах или в контейнерах.
  • Unix Sockets: высокопроизводительная локальная связь.

Пул воркеров​

RoadRunner поддерживает пул воркеров. Каждый воркер — это отдельный PHP-процесс, который остаётся живым после обработки запроса. Это означает, что ваше приложение (Laravel, Symfony и т.д.) загружается только один раз.

Конфигурация пула (.rr.yaml)​

Ключевые параметры управления жизненным циклом воркеров:

  • num_workers: количество запускаемых рабочих процессов.
  • max_jobs: количество запросов, которые воркер обрабатывает перед автоматическим завершением и заменой (предотвращает утечки памяти).
  • max_memory: мягкий лимит памяти; воркер заменяется после запроса, если лимит превышен.
  • ttl: максимальное время жизни воркера.
  • idle_ttl: максимальное время простоя воркера.
  • pool.debug: если установлено в true, для каждого запроса создаётся новый воркер (полезно при разработке).

Реализация PHP-воркера​

Типичный PHP-воркер использует класс Spiral\RoadRunner\Worker. Он работает в бесконечном цикле:

use Spiral\RoadRunner\Worker;
use Nyholm\Psr7\Factory\Psr17Factory;
use Spiral\RoadRunner\Http\HttpWorker;

$worker = Worker::create();
$factory = new Psr17Factory();
$httpWorker = new HttpWorker($worker, $factory, $factory, $factory);

while ($request = $httpWorker->waitRequest()) {
try {
$response = $factory->createResponse(200)->withBody($factory->createStream('Hello RoadRunner!'));
$httpWorker->respond($response);
} catch (\Throwable $e) {
$httpWorker->getWorker()->error((string)$e);
}
}

Ключевые плагины​

HTTP Plugin​

  • Middleware: поддержка middleware на уровне Go (заголовки, сжатие, статические файлы).
  • Response Streaming: позволяет отправлять большие ответы клиенту инкрементально.
  • SSL/TLS: встроенная поддержка HTTPS и HTTP/2.

Key-Value (KV) Plugin​

Предоставляет унифицированный интерфейс для кэширования и управления состоянием между воркерами.

  • Драйверы: redis, memcached, boltdb (файл), memory.

Jobs (Queues) Plugin​

Централизованное потребление и управление задачами в рамках Go-процесса.

  • Драйверы: amqp, beanstalk, redis, sqs, nats, boltdb, memory.

Service Plugin​

Позволяет запускать любой бинарный файл или скрипт как «sidecar»-процесс (например, пользовательский Go-демон или Python-скрипт) и следить за его работоспособностью.

Locks Plugin​

Предоставляет распределённые блокировки для синхронизации доступа к общим ресурсам между несколькими воркерами или экземплярами RoadRunner.

Лучшие практики для долгоживущего PHP​

1. Управление памятью​

PHP изначально не был предназначен для долгоживущих процессов. Даже если ваш код чист, сторонние библиотеки могут допускать утечки памяти. Всегда устанавливайте max_jobs или max_memory в конфигурации пула.

2. Сброс состояния​

Статические переменные и экземпляры-одиночки (например, в Service Container Laravel) сохраняются между запросами. Необходимо вручную сбрасывать или перепривязывать сервисы, хранящие данные, специфичные для запроса.

3. Подключения к базе данных​

Соединения могут разрываться по тайм-ауту, если долго не используются. Убедитесь, что ваш клиент БД поддерживает переподключение, или используйте настройку ttl RoadRunner для обновления воркеров.

4. Буферизация вывода​

Избегайте прямого использования echo или print — они могут повредить бинарный протокол. Используйте объекты ответов PSR-7. RoadRunner 2.0+ автоматически перенаправляет STDOUT в STDERR для смягчения этой проблемы.

Мониторинг и проверки работоспособности​

Плагин status предоставляет возможности мониторинга:

  • /health: проверка жизнеспособности (работает ли сервер RR?).
  • /ready: проверка готовности (есть ли хотя бы один свободный воркер для обработки запросов?).

Обычно интегрируются с Kubernetes или другими оркестраторами для автоматического масштабирования и управления состоянием.

Интеграция с Temporal​

RoadRunner является основным PHP-воркером для Temporal — движка оркестрации с открытым исходным кодом для состояний и длительных рабочих процессов. Это позволяет строить сложные распределённые системы на стандартной логике PHP.