На эту тему было опубликовано множество статей из различного рода источников и у многих заметил тенденцию когда каждый из трёх упомянутых технологий значительно лидирует по сравнению с остальными. Тем более что у многих показаны какие-то дикие результаты в виде 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/roadrunner2024.3.4
spiral/roadrunner-cli2.7.1
spiral/roadrunner-http3.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 будет "прогревать", какие запоминать, а какие инициализировать в процессе. Вы можете с лёгкостью проверить это на своих кейсах.
