На эту тему было опубликовано множество статей из различного рода источников и у многих заметил тенденцию когда каждый из трёх упомянутых технологий значительно лидирует по сравнению с остальными. Тем более что у многих показаны какие-то дикие результаты в виде 1к запросов в секунду...
И мне захотелось всё проверить своими руками...
OpenSwoole vs Swoole
Начну с рассказа почему выбрал именно OpenSwoole, а не Swoole.
Причина оказалась банально простой - Swoole не установился. Да, он скачался, да, выполнил make, но он не смог сам установиться в PHP запросив ручное копирование файла swoole.so
и его указание в php.ini
. Мне не хотелось этого делать. К тому же, OpenSwoole сделал всё сам, а, учитывая всё те же многочисленные статьи сравнения, их производительность идёт бок о бок друг с другом, так что...
Окружение
Сервер
Тип: VPS
Процессор: Intel Core Broadwell 2.6 GHz, 2 ядра (точную модель не знаю)
Оперативная память: 4Gb
Диск: SSD NVMe
Ось: Ubuntu 24.04
Nginx: 1.24.0 (используется ProxyPass)
PHP: 8.4.4
Ширина канала: 500 Mbps
Местоположение: Netherlands
Клиент
Клиент - это окружение, с которого будут запускаться стресс-тесты
Тип: Desktop
Процессор: Intel Core i9-11900F, 16 ядер
Оперативная память: 64Gb
Диск: SSD 525/500 R/W
Ось: Windows 11 Pro
PHP 8.4.4
Ширина канала: 750 Mbps
Местоположение: Россия
Приложение и зависимости
Laravel 11.43.2
Laravel Octane 2.8.0
Pest 3 + Pest Stressless
laravel new test && cd test
composer require --dev pestphp/pest-plugin-laravel pestphp/pest-plugin-stressless
Роут для проверки:
// routes/api.php
app('router')->get('test', TestController::class);
// TestController
class TestController
{
public function __invoke()
{
return response()->noContent();
}
}
APP_ENV = production
APP_DEBUG = false
Команды тестирования
Запуск тестов осуществлялся в 10 потоков по 5, 10 и 30 секунд следующими командами:
./vendor/bin/pest stress test.***/api/test --concurrency=10 --duration=5
./vendor/bin/pest stress test.***/api/test --concurrency=10 --duration=10
./vendor/bin/pest stress test.***/api/test --concurrency=10 --duration=30
Nginx
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
server_name test.***;
server_tokens off;
root /home/user/test.***/current/public;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.php;
charset utf-8;
location /index.php {
try_files /not_exists @octane;
}
location / {
try_files $uri $uri/ @octane;
}
location ~* \.(eot|otf|ttf|woff|woff2|png|jpg|css)$ {
add_header Access-Control-Allow-Origin *;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log off;
error_page 404 /index.php;
location @octane {
set $suffix "";
if ($uri = /index.php) {
set $suffix ?$query_string;
}
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header Scheme $scheme;
proxy_set_header SERVER_PORT $server_port;
proxy_set_header REMOTE_ADDR $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_pass http://127.0.0.1:9000$suffix;
}
location ~ /\.(?!well-known).* {
deny all;
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/test.***/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/test.***/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = test.***) {
return 301 https://$host$request_uri;
} # managed by Certbot
server_name test.***;
listen [::]:80;
listen 80;
return 404; # managed by Certbot
}
Установка и запуск
RoadRunner
На момент публикации поста актуальные версии зависимостей Spiral, на которых производилось тестирование, следующие:
spiral/roadrunner
2024.3.4
spiral/roadrunner-cli
2.7.1
spiral/roadrunner-http
3.5.1
Supervisor
[program:test]
process_name=%(process_num)02d
command=php -d variables_order=EGPCS /home/user/test/current/artisan octane:start --host=127.0.0.1 --rpc-port=6001 --port=9000 --server=roadrunner
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=user
redirect_stderr=true
stdout_logfile=/home/user/test/shared/storage/logs/octane.log
stopwaitsecs=3600
stdout_logfile_maxbytes = 10MB
stdout_logfile_backups = 5
Загрузка исполняемого файла
composer require spiral/roadrunner-cli spiral/roadrunner-http
php artisan octane:install --server=roadrunner
Тестирование
Test Duration ............................................................................ 5.09 s
Test Concurrency ............................................................................. 10
Requests Count ....................................................... 102.04 reqs/s 519 requests
Success Rate ............................................................................ 100.0 %
DNS Lookup Duration ............................... 104.21.96.1, 104.21.64.1, (+ 12 more) 0.00 ms
TLS Handshake Duration .................................................................. 0.00 ms
Request Duration ....................................................................... 91.25 ms
— Upload 0.0 % .................................................... 0.00 MB/req 0.00 MB/s 0.00 ms
— TTFB 99.9 % — including server processing time ....................................... 91.20 ms
— Download 0.0 % .................................................. 0.00 MB/req 0.05 MB/s 0.00 ms
Test Duration ........................................................................... 10.09 s
Test Concurrency ............................................................................. 10
Requests Count ...................................................... 100.65 reqs/s 1016 requests
Success Rate ............................................................................ 100.0 %
DNS Lookup Duration ............................... 104.21.96.1, 104.21.64.1, (+ 12 more) 0.00 ms
TLS Handshake Duration .................................................................. 0.00 ms
Request Duration ....................................................................... 90.01 ms
— Upload 0.0 % .................................................... 0.00 MB/req 0.00 MB/s 0.00 ms
— TTFB 100.0 % — including server processing time ...................................... 90.00 ms
— Download 0.0 % .................................................. 0.00 MB/req 0.05 MB/s 0.00 ms
Test Duration ........................................................................... 30.08 s
Test Concurrency ............................................................................. 10
Requests Count ...................................................... 101.59 reqs/s 3056 requests
Success Rate ............................................................................ 100.0 %
DNS Lookup Duration ............................... 104.21.96.1, 104.21.64.1, (+ 12 more) 0.00 ms
TLS Handshake Duration .................................................................. 0.00 ms
Request Duration ....................................................................... 92.12 ms
— Upload 0.0 % .................................................... 0.00 MB/req 0.00 MB/s 0.00 ms
— TTFB 99.9 % — including server processing time ....................................... 92.04 ms
— Download 0.0 % .................................................. 0.00 MB/req 0.05 MB/s 0.00 ms
OpenSwoole
Supervisor
[program:test]
process_name=%(process_num)02d
command=php -d variables_order=EGPCS /home/user/test/current/artisan octane:start --host=127.0.0.1 --port=9000 --server=swoole
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=user
redirect_stderr=true
stdout_logfile=/home/user/test/shared/storage/logs/octane.log
stopwaitsecs=3600
stdout_logfile_maxbytes = 10MB
stdout_logfile_backups = 5
Загрузка исполняемого файла
apt update
apt install -y software-properties-common && add-apt-repository ppa:openswoole/ppa -y
apt install -y libpq-dev
apt install -y php8.4-openswoole
Тестирование
Test Duration ............................................................................ 5.08 s
Test Concurrency ............................................................................. 10
Requests Count ....................................................... 109.77 reqs/s 558 requests
Success Rate ............................................................................ 100.0 %
DNS Lookup Duration ............................... 104.21.64.1, 104.21.96.1, (+ 12 more) 0.00 ms
TLS Handshake Duration .................................................................. 0.00 ms
Request Duration ....................................................................... 86.75 ms
— Upload 0.0 % .................................................... 0.00 MB/req 0.00 MB/s 0.00 ms
— TTFB 100.0 % — including server processing time ...................................... 86.75 ms
— Download 0.0 % .................................................. 0.00 MB/req 0.06 MB/s 0.00 ms
Test Duration ........................................................................... 10.08 s
Test Concurrency ............................................................................. 10
Requests Count ...................................................... 113.44 reqs/s 1144 requests
Success Rate ............................................................................ 100.0 %
DNS Lookup Duration ............................... 104.21.64.1, 104.21.96.1, (+ 12 more) 0.00 ms
TLS Handshake Duration .................................................................. 0.00 ms
Request Duration ....................................................................... 84.89 ms
— Upload 0.0 % .................................................... 0.00 MB/req 0.00 MB/s 0.00 ms
— TTFB 99.8 % — including server processing time ....................................... 84.73 ms
— Download 0.0 % .................................................. 0.00 MB/req 0.06 MB/s 0.00 ms
Test Duration ........................................................................... 30.08 s
Test Concurrency ............................................................................. 10
Requests Count ...................................................... 116.79 reqs/s 3513 requests
Success Rate ............................................................................ 100.0 %
DNS Lookup Duration ............................... 104.21.64.1, 104.21.96.1, (+ 12 more) 0.00 ms
TLS Handshake Duration .................................................................. 0.00 ms
Request Duration ....................................................................... 81.73 ms
— Upload 0.0 % .................................................... 0.00 MB/req 0.00 MB/s 0.00 ms
— TTFB 99.9 % — including server processing time ....................................... 81.66 ms
— Download 0.0 % .................................................. 0.00 MB/req 0.05 MB/s 0.00 ms
FrankenPHP
Supervisor
[program:test]
process_name=%(process_num)02d
command=php -d variables_order=EGPCS /home/user/test/current/artisan octane:start --host=127.0.0.1 --admin-port=2019 --port=9000 --server=frankenphp
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=user
redirect_stderr=true
stdout_logfile=/home/user/test/shared/storage/logs/octane.log
stopwaitsecs=3600
stdout_logfile_maxbytes = 10MB
stdout_logfile_backups = 5
Загрузка исполняемого файла
php artisan octane:install --server=frankenphp
Тестирование
Test Duration ............................................................................ 5.08 s
Test Concurrency ............................................................................. 10
Requests Count ........................................................ 113.1 reqs/s 574 requests
Success Rate ............................................................................ 100.0 %
DNS Lookup Duration .............................. 104.21.112.1, 104.21.96.1, (+ 12 more) 0.00 ms
TLS Handshake Duration .................................................................. 0.00 ms
Request Duration ....................................................................... 84.14 ms
— Upload 0.0 % .................................................... 0.00 MB/req 0.00 MB/s 0.00 ms
— TTFB 99.9 % — including server processing time ....................................... 84.09 ms
— Download 0.0 % .................................................. 0.00 MB/req 0.06 MB/s 0.00 ms
Test Duration ........................................................................... 10.08 s
Test Concurrency ............................................................................. 10
Requests Count ......................................................... 111 reqs/s 1119 requests
Success Rate ............................................................................ 100.0 %
DNS Lookup Duration .............................. 104.21.112.1, 104.21.96.1, (+ 12 more) 0.00 ms
TLS Handshake Duration .................................................................. 0.00 ms
Request Duration ....................................................................... 87.20 ms
— Upload 0.0 % .................................................... 0.00 MB/req 0.00 MB/s 0.00 ms
— TTFB 100.0 % — including server processing time ...................................... 87.17 ms
— Download 0.0 % .................................................. 0.00 MB/req 0.05 MB/s 0.00 ms
Test Duration ........................................................................... 30.08 s
Test Concurrency ............................................................................. 10
Requests Count ...................................................... 116.16 reqs/s 3494 requests
Success Rate ............................................................................ 100.0 %
DNS Lookup Duration .............................. 104.21.112.1, 104.21.96.1, (+ 12 more) 0.00 ms
TLS Handshake Duration .................................................................. 0.00 ms
Request Duration ....................................................................... 84.35 ms
— Upload 0.0 % .................................................... 0.00 MB/req 0.00 MB/s 0.00 ms
— TTFB 99.8 % — including server processing time ....................................... 84.22 ms
— Download 0.0 % .................................................. 0.00 MB/req 0.05 MB/s 0.00 ms
Результаты
Для сравнения были построены два графика: среднее время и количество запросов в секунду.


Как показала практика, RoadRunner самый медленный из трёх подопытных. Его просадка составляет около 6-10 мс на запрос и около -10 запросов в секунду по сравнению с двумя другими. А вот OpenSwoole идёт рядом с FrankenPHP.
Установка
Самая простая установка у FrankenPHP - его скачивает сам Laravel Octane и не требует вообще никаких дополнительных зависимостей.
Слегка более сложная установка у RoadRunner - нужно вручную установить зависимости, а также скачать исполняемый файл через внешнюю команду зависимости.
Наиболее сложная установка у Swoole и OpenSwoole - они требуют установки дополнительных компонентов в операционную систему, подключения репозитория, а также сборки зависимостей из исходников с последующей установкой в PHP в виде расширения.
Заключение
Какой из них использовать для своих нужд - определяйте исходя из своего проекта. Тесты проводились на "чистой" свеже-установленной версии Laravel. В случае наличия какой-либо логики поведение не сильно, но может отличаться, так как всё зависит от того, какие классы Octane будет "прогревать", какие запоминать, а какие инициализировать в процессе. Вы можете с лёгкостью проверить это на своих кейсах.