О чем статья
Когда дело доходит до запуска PHP-приложений, выбор правильного веб-сервера критически важен. Чтобы достоверно оценить производительность популярных серверов мы тестировали их не на синтетических, а на реальных данных. Мы не хотели составлять свой рейтинг веб-серверов для запуска php-приложений. Нашей задачей было показать условия, при которых тот или иной веб-сервер продемонстрирует лучшие результаты.
Приложения для запуска php: 30 лет эволюции
В начале был CGI. Это была одна из первых технологий для запуска серверных скриптов, появившаяся в 90-х. CGI поддерживает разные языки, что делает этот интерфейс весьма универсальным, но со своими недостатками. Например, на каждый запрос сервер создает отдельный процесс для каждого CGI-скрипта, что приводит к перерасходу системных ресурсов и сильно сказывается на производительности и скорости ответа сервера. Известной проблемой также является запуск скрипта с правами пользователя веб-сервера. Т.е. при неправильной настройке сервера CGI-скрипт может получить доступ не только к файлам и ресурсам другого приложения, но и к логам и конфигурации сервера, что создает потенциальную уязвимость.
Чтобы решить эти проблемы, был разработан Apache и модуль mod_php, который позволил запускать PHP-код непосредственно внутри веб-сервера и настроить индивидуальные права доступа к файлам для каждого хоста. Хотя на каждый запрос по-прежнему создавался отдельный процесс, часть данных кэшировалась, что существенно ускоряло выполнение по сравнению с CGI. Это давало значительный прирост в скорости.
Apache + mod_php стал популярен благодаря своей простоте конфигурации. Apache до сих пор является одним из популярных веб-серверов для web и часто используется для создания чего-то на скорую руку и без особого конфигурирования.
       
Популярность и доли рынка web-серверов.
Но использовать Apache для отдачи статики не лучшее решение: даже для получения картинки будет использован «тяжелый» (со всеми модулями вроде mod_php) обработчик.
Хорошей практикой считается использование Apache вместе с Nginx. Nginx эффективно справляется с отдачей статики, а запросы требующие выполнения php кода перенаправляет на Apache. Это значительно уменьшает потребление памяти и повышает скорость обработки запросов.
       
Схема обработки запроса web-сервером.
Связка Nginx и Apache с mod_php дает значительный прирост производительности, но модуль mod_php имеет узкое место: он запускает интерпретатор php в контексте каждого процесса Apache, что сильно увеличивает использование ресурсов.
Для более эффективного выполнения php был разработан PHP-FPM (FastCGI Process Manager) — это расширенная версия FastCGI, разработанная для увеличения производительности и надежности в средах с высокой нагрузкой. В отличие от mod_php, FPM запускает пул рабочих процессов, которые обслуживают запросы независимо от самого веб-сервера. Нужно иметь в виду, что для получения максимального быстродействия требуется детальная настройка. Также стоит учесть что некоторые CMS (WordPress, 1С-Битрикс: Управление сайтом) потребуют дополнительного конфигурирования так как часть правил хранится в файлах .htaccess (т.е. рассчитаны на запуск именно через Apache).
Можно ли что то еще сделать для ускорения работы PHP-скриптов? Этот вопрос задал себе не один разработчик. В поисках решения были найдены технологии, которые кардинально изменили подход к обработке запросов:
- 
	
Поддержка долгоживущих процессов. В отличии от традиционного подхода где приложение инициализируется каждый раз при новом запросе, можно один раз загрузить все приложение в память и использовать для обработки входящих запросов.
 - 
	
HTTP-сервер на уровне приложения. Устраняет дополнительный слой между сервером и приложением, снижая накладные расходы.
 - 
	
Многопоточность. Позволяет приложениям обрабатывать больше запросов одновременно в рамках одного процесса.
 - 
	
Минимизация накладных расходов на взаимодействие с FastCGI. Убирая взаимодействие с FastCGI и работая с 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 написано множество статей и проведена уйма тестов. Например:
- 
	
Сравниваем PHP FPM, PHP PPM, Nginx Unit, React PHP и RoadRunner
 - 
	
Mod_php vs php-fpm Performance Benchmark [Surprising Results]
 - 
	
Apache & PHP system resource usage | mpm_prefork + mod_php vs. mpm_event + php-fpm
 
Env-переменные
| 
		 Параметр  | 
	
		 Значение  | 
| 
		 APP_ENV  | 
	
		 production  | 
| 
		 APP_DEBUG  | 
	
		 false  | 
| 
		 RESPONSE_CACHE_ENABLED  | 
	
		 true  | 
Кэширование конфигов и роутов
- «php artisan optimize»
 
Среда тестирования
| 
		 Virtualization  | 
	
		 WSL  | 
| 
		 CPU  | 
	
		 8 cores (2.8GHz)  | 
| 
		 RAM  | 
	
		 8Gb  | 
| 
		 OS  | 
	
		 Ubuntu  | 
Конфигурация MySQL
| 
		 Параметр  | 
	
		 Значение  | 
| 
		 tmp_table_size  | 
	
		 512M  | 
| 
		 max_heap_table_size  | 
	
		 512M  | 
| 
		 sort_buffer_size  | 
	
		 64M  | 
| 
		 read_rnd_buffer_size  | 
	
		 1M  | 
| 
		 max_connections  | 
	
		 500  | 
| 
		 max_user_connections  | 
	
		 500  | 
Все контейнеры и результаты замеров опубликованы в нашем GitHub.
Инструменты тестирования
Само тестирование проводилось с помощью Yandex Tank при следующей конфигурации:
  load_profile:
    load_type: rps
    schedule: line(10, 300, 60s) const(100, 60s)
  instances: 300
В данном случае мы явно ограничивает Yandex Tank в количестве инстансов, чтобы не добиться появления 110 кодов ответов, а проверить какой RPS способен выдавать сервер в заданной конфигурации.
В рамках тестирования мы проверяли следующие сервера приложений:
- 
	
Apache(mod_php)
 - 
	
PHP-FPM
 - 
	
FrankenPHP
 - 
	
RoadRunner
 - 
	
Swoole
 - 
	
Nginx-UNIT
 
PHP-PM не участвовал в сравнении так как последний релиз был в 2022 и сейчас часть классов из пакета React\Http не совместима с новыми версиями Psr\Http.
Общие результаты тестирования
| 
		 Тип  | 
	
		 AVG CPU (%)  | 
	
		 AVG RAM (mb)  | 
	
		 AVG RPS  | 
	
		 Результат yandex tank  | 
| 
		 Swoole  | 
	
		 45  | 
	
		 752  | 
	
		 152.5  | 
	|
| 
		 FrankenPHP  | 
	
		 68  | 
	
		 954  | 
	
		 140.7  | 
	|
| 
		 RoadRunner  | 
	
		 60  | 
	
		 638  | 
	
		 131.5  | 
	|
| 
		 Nginx Unit  | 
	
		 87  | 
	
		 2384  | 
	
		 39.1  | 
	|
| 
		 Apache+mod_php  | 
	
		 89  | 
	
		 5277  | 
	
		 37.5  | 
	|
| 
		 PHP-FPM  | 
	
		 87  | 
	
		 3500  | 
	
		 37.3  | 
	
       
Нагрузка на 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:
- 
	
PHP-FPM – https://clck.ru/3DeQ32
 - 
	
Apache+mod_php – https://clck.ru/3DeQbP
 
Время ответа от сервера в случае с Apache возрастает до 8 сек. В то время как PHP-FPM стабильно отдает страницы за 200-300 мс.
       
Результат тестирования phpinfo с Apache+mod_php
       
Результат тестирования phpinfo с PHP-FPM
Тестирование сложных приложений, таких как Bagisto, показывает, что при динамических нагрузках разница между PHP-FPM и mod_php минимальна.
Во второй группе (FrankenPHP, Swoole, RoadRunner) — долгоживущие процессы. Они обеспечивают существенное снижение потребления ресурсов и значительный прирост RPS по сравнению с первой группой. Однако важно учитывать, что приложение должно быть адаптировано для работы с серверами, которые загружаются в память один раз и продолжают функционировать без повторной инициализации.
Сообщество и поддержка
Приложения, такие как Swoole, RoadRunner, FrankenPHP и Nginx Unit, пользуются активной поддержкой сообщества разработчиков. Давайте сравним уровень этой поддержки.
| 
		 Сервер  | 
	
		 Количество звезд  | 
	
		 Количество мейнтейнеров  | 
	
		 Количество релизов (за год)  | 
	
		 Количество созданных issue (за год)  | 
	
		 Процент закрытых issue  | 
| 
		 18.4k  | 
	
		 151  | 
	
		 5  | 
	
		 207  | 
	
		 95  | 
|
| 
		 7.9k  | 
	
		 53  | 
	
		 20  | 
	
		 112  | 
	
		 74  | 
|
| 
		 6.8k  | 
	
		 83  | 
	
		 20  | 
	
		 366  | 
	
		 73  | 
|
| 
		 5.4k  | 
	
		 46  | 
	
		 7  | 
	
		 236  | 
	
		 61  | 
Выводы
- 
	
Apache mod_php лучше использовать вместе с Nginx в качестве сервера для статики в проектах где нет серьезных нагрузок и ничего не хочется конфигурировать.
 - 
	
PHP-FPM оптимален для большинства стандартных и даже высоконагруженных проектов благодаря широкому использованию и активной поддержке сообщества.
 - 
	
NGINX Unit обеспечивает производительность, близкую к PHP-FPM, но обладает дополнительными преимуществами — поддержка нескольких языков и возможность запуска нескольких серверов, что делает его отличным выбором для микросервисных архитектур.
 
Swoole, FrankenPHP и RoadRunner хорошо подходят для высоконагруженных и асинхронных приложений, позволяя использовать долгоживущие процессы и снижая накладные расходы на инициализацию приложения. Однако такие решения требуют, чтобы приложение было адаптировано к работе с долгоживущими процессами. Из трех решений Swoole выделяется как наиболее популярное в сообществе и демонстрирует лучшую производительность и более низкое потребление ресурсов в наших тестах.
Статьи по теме






