PHP - рецепты и настройка под большие нагрузки
![]()
PHP, на сегодняшний день, это одна из самых популярных платформ для создания Web приложений. Нет смысла в очередной раз упоминать о многочисленных монстрах современного интернет, основой которых служит PHP.
PHP - достаточно производительная платформа (если сравнивать с альтернативными решениями, хотя все очень зависит от реализации), к тому же является масштабируемой (опять же, если реализация не хромает). Вопрос производительности и масштабируемости - это конечно дело приложения и его архитектуры, но тем не менее существуют некоторые советы, позволяющие сделать Ваше приложение более эффективным.
В этой статье мы рассмотрим общие практики и советы при построении нагруженных систем на основе PHP.
Связка с Web сервером
Существует несколько способов связать PHP с Web сервером:
CGI
CGI - стандартный протокол для запуска приложений в связке с Web сервером. Суть его заключается в следующем:
- Запрос приходит к Web серверу
- Сервер запускает php-cgi
- Исполняется основное приложение и генерируется HTTP ответ
- Ответ передается Web серверу и php-cgi процесс уничтожается
Этот подход весьма ресурсоемкий, т.к. приходится создавать процессы php-cgi при каждом запросе.
FastCGI
FastCGI - обертка для CGI, которая сохраняет все его возможности. Отличием от CGI является более экономное использование ресурсов и, следовательно, выигрышь в производительности. Это достигается путем создания fastCGI контейнера, который эффективно управляет очередью запросов и созданием дочерних процессов. К тому же, это позволяет вынести подсистему PHP на отдельный узел (отличный от основного Web сервера).
SAPI
Этот подход заключается в том, что PHP компилирается в модуль Web сервера и т.о., становится его частью. Этот подход является наиболее производительным, т.к. экономит ресурсы на отдельных процессах PHP. Минусом этого подхода является то, что не многие Web серверы поддерживают этот метод. Одним из них является Apache, который сам по себе является очень тяжеловесным решением.
Исходя из этого, наиболее оптимальным решением для крупных систем является использование протокола FastCGI. Это удобное, гибкое и производительное решение.
Прекомпилирование и оптимизация
PHP - это интерпретатор, поэтому при каждом запросе Ваше приложение постоянно интерпретируется и компилируется. Это может быть весьма ощутимым, когда Ваше приложение содержит много кода и подключаемых файлов.
Существует несколько технологических решений этой проблемы:
eAccelerator
![]()
Это одно из самых популярных решений, которое помимо хранения кеша компилированного кода еще и выполняет базовую оптимизацию PHP приложения. Подробнее - на официальном сайте.
APC
Помимо кеширования промежуточного кода, APC предоставляет еще и функционал по доступу к разделяемой памяти (что является очень эффективным средством для кеширования). Официальный сайт.
Zend Platform
![]()
Это многофункциональное платное решение от Zend. Помимо кеширования кода и оптимизации исполнения, этот продукт позволяет кешировать данные/контент, оптимизировать загрузку и использовать преимущества асинхронной обработки. Официальный сайт.
Настройка PHP
Первое и самое главное - собирайте только те модули, которые действительно нужны для Вашего приложения.
Есть ряд стандартных параметров PHP о которых стоит упомянуть:
- memory_limit - не стоит устанавливать этот параметр слишком большим. Если Ваша страница съедает по 512 Мб памяти во время генерации, то Вам стоит задуматься об архитектурных изменениях. Значения в 32…64Мб должно быть достаточно.
- display_errors = Off и error_log = /var/log/php - это скорее обязательное требование для продуктивной среды, чем совет. Эти настройки отключают вывод ошибок на экран и собирают их в лог файл.
- upload_max_filesize и post_max_size - максимальный размер загружаемых файлов и POST запросов - удостоверьтесь, что эти параметры не крупнее, чем требуется для Вашего приложения. Если Вы не используете загрузку - выключите ее: file_uploads = Off
- zlib.output_compression = Off и zlib.output_compression_level = -1 - включите компрессию контента. На первый взгляд компрессия будет расходовать дополнительные ресурсы процессора, но она позволяет добиться существенно меньших размеров ответа (ощутимо для посетителя). К тому же, компрессия на бекендах позволяет экономить ресурсы фронтенд-серверов.
Я что-то забыл? Что я забыл?


Думаю треба додати, що код потрібно писати правильно )), а то навіть хайлоад з повними наворотами не переживе кривого коду ))
+ думаю можна додати MemCached
Приведенные выше параметры настроек PHP весьма спорные и требуют уточнения.
memory_limit - нет универсального рецепта, каким должно быть это значение. Рекомендую на этапе оптимизации при выводе каждой страницы мерять пиковое значение потребленной памяти (с помощью xdebug). Если полученное значение выглядит аномально большим, то тогда придется брать профайлер и ковырять
display_errors. До последнего нужно держать это директиву со значением On, да еще и ставить error_reporting(E_ALL | E_STRICT). Приложение, которое не генерирует сообщения об ошибках, работает гораздо быстрее. К тому же, это подталкивает к общей аккуратности и выбработке хорошего стиля программирования.
Когда все протестировано на production-сервере, только тогда можно делать display_errors = Off.
zlib.output_compression. Как мне кажется, если идет речь про проекты с большими нагрузками (судя по заголовку статьи), то делать компрессию на backend-е архитектурно не верно. Лучше это поручить reverse-proxy (например, ранее обсуждаемый здесь nginx). Он прекрасно справится с этой задачей и будет расходовать время процессора в некритичном месте. К тому же, прокси можно настроить для кеширования и сжатия js и css, что также даст немалый выигрыш в скорости загрузки страницы.
Спасибо за статью.
Есть некоторые моменты, с которыми не особенно согласен:
>Исходя из этого, наиболее оптимальным решением для крупных систем является >использование протокола FastCGI. Это удобное, гибкое и производительное решение.
Тут все зависит от характера нагрузки на сервер.
По результатам моих тестов, если нагрузка на систему состоит из множества запросов с маленьким телом ответа (1-5Kb), то использование apache+mod_php давало выигрыш около 10% по сравнению с fastcgi
@Katod
?
Справедливое замечание, спасибо.
Думаю как раз поэтому, популярность все больше получает fastCGI, Вы часто сталкиваетесь со страницей размером 1…5Кб
@point
Спасибо, одно уточнение:
В крупных системах количество различных узлов растет не равномерно. Количество бекендов обычно превышает все остальные сервера вместе взятые (зачастую, но не всегда - опять таки нет стандартного случая), или, по крайней мере, оно больше количества фронт-серверов.
Когда у Вас 1 или 2 бекенда, возможно проще делать компрессию на фронтенде или проксирующем сервере. Но когда у Вас несколько сотен бекендов, этот узел просто не справится с нагрузкой. Именно поэтому, лучше компрессию динамики выносить на сам PHP, это разумно в терминах роста.
@Den Golotyuk
В моем случае это была не полноценная страница, а скрипты-счетчики посещаемости, не частая но встречающаяся задача.
@Katod
Согласен, для таких задач стоит серьезно задуматься над использованием SAPI модуля. Тем не менее, не стоит забывать о требовательности Apache к ресурсам, например один дочерний процес Apache с модулем PHP занимает около 1Мб памяти, в то время как в nginx’e (+fCGI) этот показатель гораздо меньше. Если для вашей системы характерно большое количество одновременных запросов - это может дать о себе знать.
@Den Golotyuk
Несомненно, решение, описанное в статье, имеет право на жизнь. Выбор стратегии сжатия контента зависит от характера приложения. Как обычно, универсального рецепта нет
Но нужно знать все пути решения проблемы, чтобы выбрать максимально удобный и производительный вариант в отдельно взятом случае.
@rootart
Тема статьи немного не про “правильность написания кода”, а уж тем более не про memcache.
@point
о том и беседуем
Абсолютно согласен
>продуктивнрй среды
опечатка
@adw0rd
поправил
Спасибо
nginx тратит на компрессию сильно меньше ресурсов, чем php. Не верите - тестируйте.
@kaa
Это акуально только тогда, когда у Вас один бекенд (маловероятно даже для средних нагрузок). Как правило при больших нагрузках установлено на порядок больше бекенд серверов, чем фронтенд. И выбор таков - распредилить нагрузку между всеми бекендами или свалить все на один фронтенд.
Стесняюсь спросить, а где собственно обещанный рецепт настойки PHP под высокие нагрузки?
1) В связке с какими Веб серверами производительность PHP будет выше?
2) Как настроить кеширование рhp-скриптов?
3) Какие модули включать, а какие нет?
@proxyd
1. Производительность php не зависит от web сервера, а зависит только от системы взаимодействия с ним - CGI, fastCGI или компилируемые модули. Про это читайте в разделе - “Связка с Web сервером”.
2. Что Вы имеете ввиду? Если кеширование кода исполнения - читайте внимательнее раздел “Прекомпилирование и оптимизация”.
3. Включать те, которые Вам нужны, иначе Ваша система работать не будет, не так ли?