Swoole и RoadRunner: PHP вне HTTP. Создание долгоживущих процессов для real-time и IoT-приложений

Сегодня я хочу рассказать, как вывести ваш PHP за рамки классического HTTP и научить его работать с долгоживущими процессами, real-time взаимодействием и IoT-устройствами. Мы разберем два мощных инструмента, Swoole и RoadRunner. И научимся создавать решения, которые раньше казались невозможными для PHP.

Почему PHP «недостаточно» для real-time и IoT?

Традиционно PHP работает в связке с веб-сервером (например, Apache или Nginx) по модели «запрос-ответ». Каждый HTTP-запрос запускает новый процесс, который умирает после отправки ответа. Это создает две проблемы:

  1. Невозможность долгосрочных операций. Например, поддержка WebSocket-соединений или обработка потоковых данных с IoT-датчиков.
  2. Накладные расходы. Постоянное создание и уничтожение процессов «съедает» ресурсы сервера.

Swoole и RoadRunner ломают эту парадигму, позволяя PHP-коду работать в режиме постоянного процесса. Давайте разберемся, как это работает.

Swoole: асинхронность и многопоточность в PHP

Swoole это расширение для PHP, написанное на C, которое добавляет поддержку асинхронного программирования, корутин и многопоточности. Оно работает как серверная платформа, позволяя запускать PHP-скрипты в фоновом режиме.

Пример 1: TCP-сервер на Swoole

Создадим простой сервер, который принимает TCP-соединения и отвечает на сообщения клиентов.

php
<?php
$server = new Swoole\Server('0.0.0.0', 9501);

// Обработка подключения
$server->on('connect', function ($server, $fd) {
    echo "Клиент $fd подключен.\n";
});

// Обработка сообщения
$server->on('receive', function ($server, $fd, $fromId, $data) {
    $server->send($fd, "Сервер получил: $data");
});

// Обработка отключения
$server->on('close', function ($server, $fd) {
    echo "Клиент $fd отключен.\n";
});

$server->start();

Запустите скрипт:

bash
php server.php

Теперь подключитесь к серверу через telnet:

bash
telnet 127.0.0.1 9501

Что происходит? Сервер работает постоянно, обрабатывая множество подключений асинхронно. Это идеально для чатов, игровых серверов или IoT-шлюзов.

RoadRunner: PHP-воркеры на стероидах

RoadRunner это менеджер процессов, написанный на Go, который управляет PHP-воркерами. В отличие от Swoole, он не требует установки расширений в PHP.

Пример 2: запуск HTTP-сервера с RoadRunner

  1. Установите RoadRunner:
bash
composer require spiral/roadrunner
./vendor/bin/rr get
  1. Создайте worker.php:
php
<?php
require __DIR__ . '/vendor/autoload.php';

use Spiral\RoadRunner\Worker;
use Spiral\RoadRunner\Http\PSR7Worker;

$worker = Worker::create();
$psr7 = new PSR7Worker($worker);

while ($req = $psr7->waitRequest()) {
    try {
        $psr7->respond(new Response(200, [], "Hello, RoadRunner!"));
    } catch (\Throwable $e) {
        $psr7->getWorker()->error((string)$e);
    }
}
  1. Запустите сервер:
bash
./rr serve

RoadRunner создаст пул воркеров, которые обрабатывают запросы, сохраняя состояние между ними. Это полезно для задач, требующих долгих вычислений, например, обработки очередей.

Swoole или RoadRunner

Параметр Swoole RoadRunner
Производительность ~1.5M запросов/сек ~120K запросов/сек
Архитектура Расширение PHP на C Go-приложение + PHP-воркеры
Асинхронность Да (корутины) Нет (синхронные воркеры)
Установка Требует компиляции composer require + бинарник
Поддержка протоколов HTTP, WebSocket, TCP, UDP HTTP, GRPC, Websockets (плагины)
Лучший сценарий Real-time, высоконагруженные системы Очереди, фоновые задачи

Создание real-time чата на Swoole

Рассмотрим практический пример: чат с WebSocket.

php
<?php
$server = new Swoole\WebSocket\Server("0.0.0.0", 9502);

// Хранилище подключенных клиентов
$clients = new \SplObjectStorage();

$server->on('open', function ($server, $request) use ($clients) {
    $clients->attach($request);
    echo "Новое подключение: {$request->fd}\n";
});

$server->on('message', function ($server, $frame) use ($clients) {
    foreach ($clients as $client) {
        if ($client->fd !== $frame->fd) {
            $server->push($client->fd, $frame->data);
        }
    }
});

$server->on('close', function ($server, $fd) use ($clients) {
    $clients->detach($fd);
    echo "Клиент $fd отключен\n";
});

$server->start();

Этот сервер поддерживает постоянные соединения и мгновенно пересылает сообщения между клиентами.

IoT-сервер на RoadRunner

Допустим, у нас есть датчики, отправляющие данные по HTTP. Создадим обработчик, который накапливает данные в Redis.

  1. Установите Redis:
bash
composer require predis/predis
  1. Модифицируем worker.php:
php
<?php
use Spiral\RoadRunner\Worker;
use Spiral\RoadRunner\Http\PSR7Worker;
use Predis\Client;

$redis = new Client(['host' => '127.0.0.1']);

while ($req = $psr7->waitRequest()) {
    $sensorData = $req->getParsedBody();
    $redis->lpush('sensor:data', json_encode($sensorData));
    $psr7->respond(new Response(200, [], 'Данные сохранены'));
}
  1. Запустите RoadRunner с 10 воркерами:
bash
./rr serve -w 10

Теперь сервер обрабатывает до 10 параллельных запросов от датчиков, сохраняя данные в Redis.

Рекомендации для разработчиков

  1. Выбирайте Swoole, если:
    • Нужна максимальная производительность.
    • Требуется асинхронная обработка (WebSocket, TCP).
    • Готовы к работе с низкоуровневым API.
  2. Выбирайте RoadRunner, если:
    • Хотите минимальной настройки.
    • Работаете с HTTP/GRPC.
    • Используете очереди (например, через плагин Jobs).
  3. Общие советы:
    • Используйте супервизоры (Supervisor или systemd) для управления процессами.
    • Мониторьте потребление памяти: долгоживущие процессы склонны к утечкам.
    • Избегайте глобальных переменных — они сохраняются между запросами.

Swoole и RoadRunner ломают стереотипы о PHP, открывая двери в мир real-time и IoT. Больше не нужно переходить на Node.js или Go для таких задач. Используйте знакомый инструмент с новыми возможностями.

Поделиться статьей:
Поддержать автора блога

Поддержка автора осуществляется с помощью специальной формы ниже, предоставленной сервисом «ЮMoney». Все платёжные операции выполняются на защищённой странице сервиса, что обеспечивает их корректность и полную безопасность.

Персональные рекомендации
Оставить комментарий