Swoole на практиці: реальні вимірювання
Swoole — це розширення PHP, написане на C, що надає цикл подій, корутини та асинхронний I/O. Це єдина зріла реалізація корутинної моделі в екосистемі PHP з багаторічним досвідом у продакшні.
Нижче наведено збірку реальних вимірювань: продакшн-кейси, незалежні бенчмарки та дані TechEmpower.
Два джерела підвищення продуктивності
Перехід від PHP-FPM до Swoole забезпечує дві незалежні переваги:
-
Stateful середовище виконання — застосунок завантажується один раз і залишається в пам’яті. Зникають накладні витрати на повторну ініціалізацію (autoload, DI-контейнер, конфігурація) при кожному запиті. Цей ефект дає виграш навіть без I/O.
-
Конкурентність корутин — поки одна корутина чекає відповіді від БД або зовнішнього API, інші обробляють запити на тому ж ядрі. Цей ефект проявляється тільки за наявності I/O і вимагає використання асинхронних клієнтів (корутинний MySQL, Redis, HTTP-клієнт).
Більшість публічних бенчмарків не розділяють ці два ефекти. Тести без БД (Hello World, JSON) вимірюють лише ефект stateful. Тести з БД вимірюють суму обох, але не дозволяють ізолювати внесок корутин.
Кожен розділ нижче вказує, який ефект переважає.
1. Продакшн: Appwrite — міграція з FPM на Swoole (+91%)
Що вимірюється: stateful середовище виконання + конкурентність корутин. Appwrite — це I/O-проксі з мінімальною CPU-роботою. Виграш забезпечується обома факторами, але ізолювати внесок корутин з публічних даних неможливо.
Appwrite — це Backend-as-a-Service (BaaS) з відкритим кодом, написаний на PHP. Appwrite надає готовий серверний API для типових задач мобільних та веб-застосунків: автентифікація користувачів, керування базою даних, зберігання файлів, хмарні функції, push-сповіщення.
За своєю природою Appwrite — це чистий I/O-проксі: майже кожен вхідний HTTP-запит перетворюється на одну або кілька I/O-операцій (запит до MariaDB, виклик Redis, читання/запис файлу), з мінімальними власними CPU-обчисленнями. Такий профіль навантаження витягує максимальну користь з переходу на корутини: поки одна корутина чекає відповіді від БД, інші обробляють нові запити на тому ж ядрі.
У версії 0.7 команда замінила Nginx + PHP-FPM на Swoole.
Умови тестування: 500 одночасних клієнтів, 5 хвилин навантаження (k6). Усі запити до ендпоінтів з авторизацією та контролем зловживань.
| Метрика | FPM (v0.6.2) | Swoole (v0.7) | Зміна |
|---|---|---|---|
| Запитів на секунду | 436 | 808 | +85% |
| Загальна кількість запитів за 5 хв | 131 117 | 242 336 | +85% |
| Час відповіді (нормальний) | 3,77 мс | 1,61 мс | −57% |
| Час відповіді (під навантаженням) | 550 мс | 297 мс | −46% |
| Частка успішних запитів | 98% | 100% | Без таймаутів |
Загальне покращення, заявлене командою: ~91% за сукупністю метрик.
Джерело: Appwrite 0.7: 91% boost in API Performance (DEV.to)
2. Продакшн: IdleMMO — 35 мільйонів запитів на день на одному сервері
Що вимірюється: переважно stateful середовище виконання. Laravel Octane запускає Swoole в режимі «один запит — один воркер», без мультиплексування I/O корутинами всередині запиту. Приріст продуктивності забезпечується тим, що Laravel не перезавантажується на кожному запиті.
IdleMMO — це PHP-застосунок (Laravel Octane + Swoole), MMORPG з 160 000+ користувачами.
| Метрика | Значення |
|---|---|
| Запитів на день | 35 000 000 (~405 req/s у середньому) |
| Потенціал (оцінка автора) | 50 000 000+ req/день |
| Сервер | 1 × 32 vCPU |
| Воркери Swoole | 64 (4 на ядро) |
| Затримка p95 до налаштування | 394 мс |
| Затримка p95 після Octane | 172 мс (−56%) |
Автор зазначає, що для менш CPU-інтенсивних застосунків (не MMORPG) той самий сервер міг би обробити значно більше запитів.
Джерело: From Zero to 35M: The Struggles of Scaling Laravel with Octane
3. Бенчмарк: PHP-FPM проти Swoole (BytePursuits)
Що вимірюється: тільки stateful середовище виконання. Тест повертає JSON без звернення до БД чи зовнішніх сервісів. Конкурентність корутин тут не задіяна — немає I/O, який можна було б виконувати паралельно. Різниця у 2,6–3x повністю обумовлена тим, що Swoole не перестворює застосунок на кожному запиті.
Незалежний бенчмарк на мікрофреймворку Mezzio (JSON-відповідь, без БД). Intel i7-6700T (4 ядра / 8 потоків), 32 ГБ RAM, wrk, 10 секунд.
| Конкурентність | PHP-FPM (req/s) | Swoole BASE (req/s) | Різниця |
|---|---|---|---|
| 100 | 3 472 | 9 090 | 2,6x |
| 500 | 3 218 | 9 159 | 2,8x |
| 1 000 | 3 065 | 9 205 | 3,0x |
Середня затримка при 1000 одночасних:
- FPM: 191 мс
- Swoole: 106 мс
Критичний момент: починаючи з 500 одночасних з’єднань, PHP-FPM почав втрачати запити (73 793 помилки сокетів при 500, 176 652 при 700). Swoole мав нуль помилок на всіх рівнях конкурентності.
Джерело: BytePursuits: Benchmarking PHP-FPM vs Swoole
4. Бенчмарк: з базою даних (kenashkov)
Що вимірюється: набір тестів з різними ефектами.
- Hello World, Autoload — чистий stateful (без I/O).
- SQL-запит, реальний сценарій — stateful + корутини.
- Swoole використовує корутинний MySQL-клієнт, що дозволяє обслуговувати
- інші запити під час очікування відповіді від БД.
Більш реалістичний набір тестів: Swoole 4.4.10 проти Apache + mod_php. ApacheBench, 100–1000 одночасних, 10 000 запитів.
| Сценарій | Apache (100 конк.) | Swoole (100 конк.) | Різниця |
|---|---|---|---|
| Hello World | 25 706 req/s | 66 309 req/s | 2,6x |
| Autoload 100 класів | 2 074 req/s | 53 626 req/s | 25x |
| SQL-запит до БД | 2 327 req/s | 4 163 req/s | 1,8x |
| Реальний сценарій (кеш + файли + БД) | 141 req/s | 286 req/s | 2,0x |
При 1000 одночасних:
- Apache впав (ліміт з’єднань, невдалі запити)
- Swoole — нуль помилок у всіх тестах
Ключове спостереження: з реальним I/O (БД + файли) різниця зменшується з 25x до 1,8–2x. Це очікувано: база даних стає спільним вузьким місцем. Але стабільність під навантаженням залишається непорівнянною.
Джерело: kenashkov/swoole-performance-tests (GitHub)
5. Бенчмарк: Symfony 7 — усі середовища виконання (2024)
Що вимірюється: тільки stateful середовище виконання. Тест без БД — корутини не задіяні. Різниця >10x пояснюється тим, що FPM створює процес на кожен запит, тоді як Swoole та FrankenPHP тримають застосунок у пам’яті та обслуговують з’єднання через цикл подій.
Тест 9 PHP-середовищ виконання з Symfony 7 (k6, Docker, 1 CPU / 1 ГБ RAM, без БД).
| Середовище виконання | проти Nginx + PHP-FPM (при 1000 конк.) |
|---|---|
| Apache + mod_php | ~0,5x (повільніше) |
| Nginx + PHP-FPM | 1x (базовий рівень) |
| Nginx Unit | ~3x |
| RoadRunner | >2x |
| Swoole / FrankenPHP (worker) | >10x |
При 1000 одночасних з’єднань Swoole та FrankenPHP у режимі worker показали на порядок вищу пропускну здатність, ніж класичний Nginx + PHP-FPM.
Джерело: Performance benchmark of PHP runtimes (DEV.to)
6. TechEmpower: Swoole — перше місце серед PHP
Що вимірюється: stateful + корутини (у тестах з БД). TechEmpower включає як JSON-тест (stateful), так і тести з кількома SQL-запитами (multiple queries, Fortunes), де корутинний доступ до БД дає реальну перевагу. Це один з небагатьох бенчмарків, де ефект корутин найбільш виразно видимий.
У TechEmpower Framework Benchmarks (Round 22, 2023) Swoole посів перше місце серед усіх PHP-фреймворків у тесті MySQL.
TechEmpower тестує реальні сценарії: серіалізацію JSON, одиничні запити до БД, множинні запити, ORM, Fortunes (шаблонізація + БД + сортування + екранування).
Джерело: TechEmpower Round 22, swoole-src README
7. Hyperf: 96 000 req/s на фреймворку Swoole
Що вимірюється: stateful середовище виконання (бенчмарк — Hello World). Hyperf повністю побудований на корутинах Swoole, і у продакшні конкурентність корутин використовується для БД, Redis та gRPC-викликів. Однак цифра 96K req/s отримана на Hello World без I/O, тобто відображає ефект stateful середовища виконання.
Hyperf — це корутинний PHP-фреймворк, побудований на Swoole. У бенчмарку (4 потоки, 100 з’єднань):
- 96 563 req/s
- Затримка: 7,66 мс
Hyperf позиціонується для мікросервісів і заявляє 5–10x перевагу над традиційними PHP-фреймворками.
Джерело: Hyperf GitHub
Підсумок: що показують реальні дані
| Тип тесту | FPM → Swoole | Основний ефект | Примітка |
|---|---|---|---|
| Hello World / JSON | 2,6–3x | Stateful | BytePursuits, kenashkov |
| Autoload (stateful проти stateless) | 25x | Stateful | Без I/O — чистий ефект збереження стану |
| З базою даних | 1,8–2x | Stateful + корутини | kenashkov (корутинний MySQL) |
| Продакшн API (Appwrite) | +91% (1,85x) | Stateful + корутини | I/O-проксі, обидва фактори |
| Продакшн (IdleMMO) | p95: −56% | Stateful | Воркери Octane, не корутини |
| Висока конкурентність (1000+) | Swoole стабільний, FPM падає | Цикл подій | Усі бенчмарки |
| Середовища Symfony (1000 конк.) | >10x | Stateful | Без БД у тесті |
| TechEmpower (тести з БД) | №1 серед PHP | Stateful + корутини | Множинні SQL-запити |
Зв’язок з теорією
Результати добре узгоджуються з розрахунками з Ефективність IO-bound задач:
1. З базою даних різниця скромніша (1,8–2x), ніж без неї (3–10x). Це підтверджує: з реальним I/O вузьким місцем стає сама БД, а не модель конкурентності. Коефіцієнт блокування у тестах з БД нижчий, оскільки CPU-робота фреймворку порівнянна з часом I/O.
2. При високій конкурентності (500–1000+) FPM деградує, а Swoole ні. PHP-FPM обмежений кількістю воркерів. Кожен воркер — це процес ОС (~40 МБ). При 500+ одночасних з’єднань FPM досягає ліміту і починає втрачати запити. Swoole обслуговує тисячі з’єднань у десятках корутин без збільшення споживання пам’яті.
3. Stateful середовище виконання усуває накладні витрати на повторну ініціалізацію. Різниця у 25x у тесті autoload демонструє вартість перестворення стану застосунку на кожному запиті у FPM. У продакшні це проявляється як різниця між T_cpu = 34 мс (FPM) та T_cpu = 5–10 мс (stateful), що драматично змінює коефіцієнт блокування і відповідно виграш від корутин (див. таблицю в Ефективність IO-bound задач).
4. Формула підтверджується. Appwrite: FPM 436 req/s → Swoole 808 req/s (1,85x). Якщо T_cpu знизився з ~30 мс до ~15 мс (stateful), а T_io залишився ~30 мс, то коефіцієнт блокування зріс з 1,0 до 2,0, що передбачає збільшення пропускної здатності приблизно в 1,5–2x. Це збігається.
Посилання
Продакшн-кейси
Незалежні бенчмарки
- BytePursuits: PHP-FPM vs Swoole
- kenashkov: swoole-performance-tests (GitHub)
- PHP runtimes benchmark — Symfony 7 (DEV.to)