Выжимаем максимум скорости из PHP

При запуске PHP-приложений крайне важно правильно выбрать веб-сервер. Чтобы объективно оценить производительность популярных решений, мы проводили тестирование не на искусственных данных, а на реальных примерах. Наша цель не заключалась в создании рейтинга веб-серверов для PHP-приложений. Мы стремились показать, в каких условиях каждый сервер сможет продемонстрировать наилучшие результаты.

Приложения для запуска php: 30 лет эволюции

Вначале появилась технология CGI, ставшая одной из первых для запуска серверных скриптов еще в 90-х. CGI поддерживала различные языки программирования, что делало её универсальной, но с определёнными недостатками. Например, для каждого запроса сервер создавал отдельный процесс для выполнения CGI-скрипта, что вызывало высокий расход системных ресурсов и снижало производительность, замедляя отклик сервера. Дополнительной проблемой был запуск скриптов с правами пользователя веб-сервера. Это означало, что при неправильной настройке CGI-скрипт мог получить доступ не только к данным других приложений, но и к конфигурационным файлам или логам сервера, создавая серьёзные уязвимости.

Чтобы устранить эти недостатки, был разработан сервер Apache и модуль mod_php. Он позволял выполнять PHP-код непосредственно внутри веб-сервера, а также задавать индивидуальные права доступа к файлам для каждого хоста. Хотя на каждый запрос по-прежнему создавался отдельный процесс, часть данных кэшировалась, что значительно ускоряло обработку запросов по сравнению с CGI. Это обеспечивало заметный прирост производительности.

Связка Apache и mod_php быстро завоевала популярность благодаря простой настройке. Apache остаётся востребованным веб-сервером и по сей день, особенно для проектов, требующих быстрой реализации и минимальной конфигурации.

Популярность и доли рынка web-серверов.

Apache не является лучшим выбором для отдачи статических файлов: даже для простой выдачи изображения используется «тяжеловесный» обработчик со всеми подключенными модулями, такими как mod_php.

Более эффективным решением считается использование Apache совместно с Nginx. В этой связке Nginx отвечает за обработку статических файлов, а запросы, требующие выполнения PHP-кода, перенаправляются на Apache. Такой подход позволяет существенно снизить потребление памяти и ускорить обработку запросов.

Схема обработки запроса web-сервером.

Схема обработки запроса web-сервером.


Работа веб-сервера в связке Nginx и Apache с использованием mod_php демонстрирует значительное увеличение производительности. Однако mod_php имеет свой недостаток: каждый процесс Apache запускает PHP-интерпретатор, что приводит к значительному росту потребления ресурсов.

Для повышения эффективности работы PHP был создан PHP-FPM (FastCGI Process Manager) — улучшенная версия FastCGI, предназначенная для увеличения производительности и надежности в условиях высокой нагрузки. В отличие от mod_php, PHP-FPM запускает пул процессов, обслуживающих запросы независимо от веб-сервера. Однако, чтобы достичь максимальной производительности, требуется тщательная настройка. Кроме того, нужно учитывать, что некоторые CMS (например, WordPress или 1С-Битрикс: Управление сайтом) могут потребовать дополнительной конфигурации, так как часть правил работы указывается в файлах .htaccess, рассчитанных на использование Apache.

Но можно ли сделать что-то еще для ускорения работы PHP-скриптов? Этот вопрос волновал не одного разработчика. В поисках решения были найдены технологии, которые кардинально изменили подход к обработке запросов:

  • Поддержка долгоживущих процессов. В отличии от традиционного подхода где приложение инициализируется каждый раз при новом запросе, можно один раз загрузить все приложение в память и использовать для обработки входящих запросов.

  • HTTP-сервер на уровне приложения. Устраняет дополнительный слой между сервером и приложением, снижая накладные расходы.

  • Многопоточность. Позволяет приложениям обрабатывать больше запросов одновременно в рамках одного процесса.

  • Минимизация накладных расходов на взаимодействие с FastCGI. Убирая взаимодействие с FastCGI и работая с php кодом нативно мы устраняем накладные расходы на обработку каждого запроса.

Рассмотрим плюсы и минусы некоторых способов запуска php приложений:

1. Apache + mod_php

Создатель: Apache Software Foundation. Написан на C.

Плюсы:

  • Лёгкость настройки. mod_php включен в в стандартную сборку apache.

  • Стабильность. Решение проверено временем и имеет большую базу готовых проектов.

Минусы:  

  • Ресурсоемкость. Модуль загружается внутри каждого процесса Apache, что сильно влияет на производительность.

  • Большое увеличение потребляемых ресурсов при высоких нагрузках.

  • Отсутствие гибкости. Не позволяет тонко настроить конфигурацию для каждого виртуального хоста или разделение ресурсов между процессами.

2. PHP-FPM (PHP FastCGI Process Manager)

Создатель: Андрей Павлин. Написан на C.

Плюсы:

  • Стал официальной частью PHP, начиная с версии 5.3.

  • №2 в списке популярных способов запуска PHP-приложений.

  • Обладает неплохой производительностью за счет масштабирования пула воркеров.

  • Возможность гибкой настройки пула.

  • Больше возможностей для отладки, включая лог медленных запросов.

Минусы:

  • Более сложная настройка по сравнению с Apache (mod_php). 

  • Необходимо настроить взаимодействие с веб-сервером (Nginx).

  • Ресурсоемкость: Каждый запрос обрабатывается отдельным PHP-процессом, что увеличивает расход оперативной памяти при высокой нагрузке. Также присутствуют накладные расходы из-за коммуникации через FastCGI.

3. PHP-PM (PHP Process Manager)

Создатель: Марк Шличтенмайер. Написан на PHP.

Плюсы:

  • Поддержка долгоживущих процессов. Вследствие чего производительность лучше чем у php-fpm.

  • Асинхронная обработка. PHP-PM использует ReactPHP для обеспечения асинхронности, что значительно ускоряет обработку запросов.

  • Автоматическая перезагрузка при изменении кода.

Минусы:

  • Необходимо следить за памятью. 

  • Требует более глубокого понимания работы асинхронного PHP.

  • Небольшое сообщество.

  • Меньше совместимости: Не поддерживает все библиотеки и расширения, использующие синхронные механизмы, такие как PDO или CURL, которые по умолчанию работают в синхронном режиме.

4. FrankenPHP 

Создатель: Кевин Дюнглас. Написан на Go.

Плюсы:

  • Поддержка долгоживущих процессов.

  • Нет необходимости в отдельном веб-сервере.

  • Поддерживает асинхронную обработку запросов.

  • Поддержка WebSocket и длительных соединений.

  • Поддерживается в laravel octane (библиотека позволяющая одной командой установить Swoole, RoadRunner или FrankenPHP, без необходимости писать код воркера) (https://github.com/laravel/octane).

Минусы:

  • Необходимо следить за памятью.

  • Необходимо перезапускать при изменении кода.

  • Требует более глубокого понимания работы асинхронного PHP.

  • Небольшое сообщество.

  • Без использования laravel octane необходимо написать код для воркера.

  • Сложная настройка. Требует более сложной настройки и внедрения в существующие проекты по сравнению с традиционными решениями например php-fpm.

5. RoadRunner

Создатель: Spiral Scout. Написан на Go.

Плюсы:

  • Поддержка долгоживущих процессов.

  • Нет необходимости в отдельном веб-сервере.

  • Асинхронность и многопоточность: поддерживает асинхронные задачи.

  • WebSocket и gRPC: Поддерживает WebSocket, gRPC и очереди для построения реальных асинхронных приложений.

  • Поддерживается в laravel octane.

Минусы:

  • Необходимо следить за памятью.

  • Необходимо перезапускать при изменении кода.

  • Требует более глубокого понимания работы асинхронного PHP.

  • Небольшое сообщество.

  • Без использования laravel octane необходимо написать код для воркера.

  • Сложная настройка.

6. Swoole

Создатель: Swoole Team. Написан на C.

Плюсы:

  • Поддержка долгоживущих процессов.

  • Нет необходимости в отдельном веб-сервере.

  • Поддерживает асинхронный ввод/вывод и корутины, и может обрабатывать высоко-конкурентные запросы.

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

  • Поддерживается в laravel octane.

Минусы:

  • Необходимо следить за памятью.

  • Необходимо перезапускать при изменении кода.

  • Требует более глубокого понимания работы асинхронного PHP.

  • Небольшое сообщество.

  • Без использования laravel octane необходимо написать код для воркера.

  • Сложная настройка.

7. NGINX Unit

Создатель: NGINX. Написан на C.

Плюсы:

  • Unit поддерживает не только PHP, но и другие языки, такие как Python, Go, Perl и Ruby.

  • Поддерживает динамическую смену конфигурации без перезапуска сервера.

  • Можно запускать несколько приложений одновременно, что удобно для микросервисов.

  • Минимизирует время простоя и облегчает управление конфигурациями.

  • Не требуется изменять приложение как в случае с долгоживущими процессами.

Минусы:

  • Меньшая производительность по сравнению с решениями для долгоживущих процессов.

  • Небольшое сообщество: Unit менее популярен по сравнению с традиционными решениями вроде PHP-FPM.

  • Ограниченные возможности для асинхронности: Хотя Unit поддерживает несколько языков и конфигураций, он все еще уступает в плане асинхронных возможностей таким решениям, как Swoole или RoadRunner.

Сравнение скорости приложений

На тему сравнения скорости приложений для запуска PHP написано множество статей и проведена уйма тестов. Например:

  1. Сравниваем PHP FPM, PHP PPM, Nginx Unit, React PHP и RoadRunner

  2. Тест производительности во время выполнения PHP

  3. Mod_php vs php-fpm Performance Benchmark [Surprising Results]

  4. Apache & PHP system resource usage | mpm_prefork + mod_php vs. mpm_event + php-fpm

  5. Comparing PHP-FPM, NGINX Unit, and Laravel Octane

Однако большая часть таких тестов являются сильно синтетическими, т.е. тестируемые проекты мало похожи на то, с чем вы в итоге будете иметь дело (например, первая статья, где сервер отвечает json`ом без запросов к БД или вторая, где тестируется phpinfo). Чтобы сделать тесты более реалистичным мы взяли интернет-магазин на базе Laravel (Laravel Framework 10.41.0) — Bagisto (v2.2.2). Сгенерировали 5000 товаров и настроили его в соответствии с инструкциями по развертыванию (включен кэш и отключен различный дебаг). 

Env-переменные

503f62340fff44f679afe08447ba286e.png

Кэширование конфигов и роутов

  • «php artisan optimize»

Среда тестирования

bc19864a77e7edf0deff7382b5d1c3cd.png

Конфигурация MySQL

2fdc4e6ed757be04cbd961c657c0f9b9.png

Все контейнеры и результаты замеров опубликованы в нашем GitHub.

Инструменты тестирования

Само тестирование проводилось с помощью Yandex Tank при следующей конфигурации:

4e88af246e3a2ebe5f85af8426d02d54.png

В данном случае мы явно ограничивает Yandex Tank в количестве инстансов, чтобы не добиться появления 110 кодов ответов, а проверить какой RPS способен выдавать сервер в заданной конфигурации.

В рамках тестирования мы проверяли следующие сервера приложений:

  • Apache (mod_php)

  • PHP-FPM

  • FrankenPHP

  • RoadRunner

  • Swoole

  • Nginx-UNIT

PHP-PM не участвовал в сравнении так как последний релиз был в 2022 и сейчас часть классов из пакета React\Http не совместима с новыми версиями Psr\Http.

Общие результаты тестирования

ebd5b6bbf9a8b83fe00b305b14f87e64.pngНагрузка на CPU

Нагрузка на CPU

График использование памяти

График использование памяти

График времени ответа сервера

График времени ответа сервера

Для более корректного сравнения серверов стоит разделить их на две группы:

  • Сервера, которые инициализируют приложение при каждом запросе: Apache mod_php, PHP-FPM, Nginx Unit.

  • Сервера с долгоживущими процессами, которые загружают приложение один раз и продолжают с ним работать: FrankenPHP, Swoole, RoadRunner.

В первой группе (Apache mod_php, PHP-FPM, Nginx Unit) разница в RPS незначительна. Однако PHP-FPM и Nginx Unit более эффективны в плане использования ресурсов. 

В тестах часто сравнивают PHP-FPM и mod_php, используя статичные данные (например, вывод phpinfo). В таких случаях PHP-FPM действительно демонстрирует прирост производительности в 300%+, что актуально только для статичных данных.

Примеры тестирования вывода phpinfo:

Время ответа от сервера в случае с Apache возрастает до 8 сек. В то время как PHP-FPM стабильно отдает страницы за 200–300 мс.

Результат тестирования phpinfo с Apache+mod_php

Результат тестирования phpinfo с Apache+mod_php

Результат тестирования phpinfo с PHP-FPM

Результат тестирования phpinfo с PHP-FPM

Тестирование сложных приложений, таких как Bagisto, показывает, что при динамических нагрузках разница между PHP-FPM и mod_php минимальна.

Во второй группе (FrankenPHP, Swoole, RoadRunner) — долгоживущие процессы. Они обеспечивают существенное снижение потребления ресурсов и значительный прирост RPS по сравнению с первой группой. Однако важно учитывать, что приложение должно быть адаптировано для работы с серверами, которые загружаются в память один раз и продолжают функционировать без повторной инициализации.

Сообщество и поддержка

Приложения, такие как Swoole, RoadRunner, FrankenPHP и Nginx Unit, пользуются активной поддержкой сообщества разработчиков. Давайте сравним уровень этой поддержки.

1f138758cb786d15439b2cc1253e543d.png

Выводы

  • Apache mod_php рекомендуется использовать вместе с Nginx в качестве сервера для статики в проектах, где нет больших нагрузок и требуется минимальная настройка.

  • PHP-FPM является оптимальным выбором для большинства типовых и даже высоконагруженных проектов благодаря его популярности и активной поддержке сообщества.

  • NGINX Unit обеспечивает производительность, сравнимую с PHP-FPM, но обладает дополнительными преимуществами: поддержка нескольких языков программирования и возможность работы с несколькими серверами. Это делает его особенно подходящим для микросервисных архитектур.

Swoole, FrankenPHP и RoadRunner отлично подходят для высоконагруженных и асинхронных приложений, так как позволяют работать с долгоживущими процессами и сокращают издержки на инициализацию приложения. Однако использование таких решений требует адаптации приложения для работы с долгоживущими процессами. Из этих трёх решений Swoole выделяется своей популярностью в сообществе, а также демонстрирует лучшую производительность и более низкое потребление ресурсов в проведённых тестах.

Наши решения и внедрения успешно зарекомендовали себя в крупных Enterprise-проектах. Мы гордимся, что наш опыт подтвержден сотрудничеством с ведущими компаниями, реализующими масштабные и сложные задачи. Ознакомиться можно здесь. 

А если ты талантливый программист и тоже хочешь работать над большими проектами, то ознакомься с нашими актуальными вакансиями — возможно, это именно то, что ты искал! :)

© Habrahabr.ru