- Советы по настройке и оптимизации Nginx и PHP-FPM
- Определить Nginx worker_processes и worker_connections
- Worker Processes
- Worker Connections
- Скрыть токены Nginx / Скрыть номер версии Nginx
- Ограничение на размер передаваемых данных сервером Nginx
- Управление кешем для статических файлов
- Проксируйте PHP запросы к PHP-FPM
- Предотвращение (запрет) доступа к скрытым файлам
- Советы по настройке и оптимизации PHP-FPM
- Файлы конфигурации PHP-FPM
- Глобальная конфигурация PHP-FPM
- Конфигурация пулов PHP-FPM
- Конфигурация менеджера процессов (Pool Process Manager) PHP-FPM
- Как ускорить приложение за счёт PHP-FPM (няшим FPM conf)
Советы по настройке и оптимизации Nginx и PHP-FPM
Thank you for reading this post, don’t forget to subscribe!
Определить Nginx worker_processes и worker_connections
Настройки по умолчанию хороши, но их стоит немного оптимизировать: max_clients = worker_processes * worker_connections .
Базовые настройки Nginx могут обрабатывать сотни одновременных соединений:
Обычно 1000 одновременных соединений на один сервер это хорошо, но порою другие части, например жесткий диск могут оказаться медленными и это приведет к тому, что Nginx будет заблокирован на операции ввода-вывода (I/O). Чтобы избежать блокировки используйте, например, следующие настройки: одни worker_process на ядро процессора :
Worker Processes
Чтобы определить сколько ядер имеет ваш процессор, введите:
В данном случае у меня четыре ядра, поэтому окончательный парамерт worker_processes устанавливаем как 4:
Worker Connections
Лично я придерживаюсь 1024 соединений на один воркер, потому что у меня нет никаких оснований для повышения этого значения. Но если например 4096 соединений в секунду не хватает, то можно попробовать удвоить 2048 соединений на процесс.
Окончательные настройки выглядят седующим образом:
Скрыть токены Nginx / Скрыть номер версии Nginx
Это хорошо из соображений безопасности — скрыть токены Nginx и скрыть номер версии Nginx, тем более если вы используете устаревшую версию Nginx. Это очень легко сделать — достаточно добавить в секцию http/server/location файла конфигурации следующую строку:
Ограничение на размер передаваемых данных сервером Nginx
Если вы хотите разрешить пользователям загружать файлы, то вы должны увеличить размер сообщения. Это может быть сделано с помощью значения client_max_body_size , которое находится в секции http/server/location файла конфигурации. По умолчанию он равен 1 Мб, но его можно увеличить, например, до 20 Мб, а также увеличить размер буфера:
Если вы получаете сообщение об ошибке, то вы знаете, что client_max_body_size слишком мало:
Управление кешем для статических файлов
Кэш браузера сохранит ресурсы и пропускную способность вашего сервера. Это несложная настройка Nginx позволит выключить ведение логов ( access log и not found log ), и установить срок истечения заголовка в 360 дней.
Если вы хотите более сложный заголовки или другие типы файлов, то вы можете настроить их отдельно.
Проксируйте PHP запросы к PHP-FPM
Вы можете использовать по умолчанию стек tcp/ip или соединение через Unix-сокет. Также необходимо установить PHP-FPM слушать точно такой же ip:port или Unix-сокет. Вот очень простой пример конфигурации (вариант с Unix-сокетом закоментирован):
Это дает возможность запуска PHP-FPM другим сервером.
Предотвращение (запрет) доступа к скрытым файлам
Это очень распространено, когда корень сервера или другие публичные каталоги имеют скрытые файлы, которые начинаются с точки (.) И, как правило, они не предназначены для пользователей сайта. Публичный каталог может содержать файлы системы контроля версий: .git , .svn ; файлы IDE : .idea ; .htaccess файлы. Настройки запещают доступ к скрытым файлам и отключают ведение логов:
Советы по настройке и оптимизации PHP-FPM
Файлы конфигурации PHP-FPM
Обычно конфигурации PHP-FPM расположенны в файле /etc/php-fpm.conf и в каталоге /etc/php-fpm.d/ . Весь пулл конфигов расопложен в дикертории /etc/php-fpm.d/ . Чтобы это работало, вы должны добавить следующую строку в php-fpm.conf :
Глобальная конфигурация PHP-FPM
Настройки emergency_restart_threshold , emergency_restart_interval и process_control_timeout по умолчанию выключены, но я считаю что их стоит влючить, например, со следующими значениями:
Что это значит? Если 10 дочерних процессов PHP-FPM завершатся с помощью SIGSEGV или SIGBUS в течении 1 минуты, то PHP-FPM перезагрузится автоматически. А также дочерним процессам установлен лимит времени реакции в 10 секунд на сигнал от мастера.
Конфигурация пулов PHP-FPM
В PHP-FPM возможно использовать отденьные пулы для каждого сайта и точно распределять ресурсы, а также использовать разных пользователей и разные группы для каждого пула. Приведем примеры конфигураци трех различнх сайтов (или фактически три части одного сайта):
/etc/php-fpm.d/site.conf
/etc/php-fpm.d/blog.conf
/etc/php-fpm.d/forums.conf
Примеры конфигурации каждого пула:
/etc/php-fpm.d/site.conf
/etc/php-fpm.d/blog.conf
/etc/php-fpm.d/forums.conf
Это просто примеры как настроить несколько различных пулов.
Конфигурация менеджера процессов (Pool Process Manager) PHP-FPM
Лучший способ использовать менеджер процессов PHP-FPM — это донамическое управление процессами, поэтому PHP-FPM запускает процессы только при необходимости. Это почти такой же подход как в Nginx с параметрами worker_processes и worker_connections . Таким образом большие значения не обеспечивают хорошего результата. Каждый процесс ест определнное количество памяти и, конечно, если у сайта очень большой трафик и много оперативной памяти на сервере, то высокие значения — это правильный выбор. Но такие серверы как VPS обычно имеют ограниченное количество памяти: 256 Мб, 512 Мб, 1024 Мб. Такого небольшого объема ОЗУ достаточно даже для очень большого трафика (даже десятки запросов в секунду), если эту память использовать с умом.
Проверим сколько процессов PHP-FPM позволит легко справляться серверу с нагрузкой. Сначала запустим Nginx и PHP-FPM и загрузим несколько страниц PHP , желательно самые тяжелые. Затем проверим сколько использует памяти процесс PHP-FPM — в Linux можно воспользоваться утилитами top или htop . Предположим что наш сервер имеет 512 Мб оперативной памяти и 220 Мб может быть использованно PHP-FPM , каждый процесс использует 24 Мб оператичной памяти (некоторые CMS с плагинами могут легко кушать 20-40 Мб на один запрос или даже больше). Затем просто вычислим значние max_children для сервера:
Приемлемым значнием pm.max_children будет 9. Это значние основанно на среднем значении и возможно далее его необходимо будет изменить, когда вы заметите длительное время использования памяти процессом. После быстрого тестирования несложно выбрать значния pm.start_servers value , pm.min_spare_servers и pm.max_spare_servers .
Окончательная конфигурация нашего примера может выглядеть следующим образом:
Максималоное количество запросов на процесс по умолчанию не ограничено, но хорошо бы установить какое-нибудь небольшое значение, например 200, и избежать проблем с памятью. Такого вида настрока может обрабарывать большое количество запросов, даже если значение параметра невелико.
Подробный разбор параметров конфигурационных файлов:
Как ускорить приложение за счёт PHP-FPM (няшим FPM conf)
Сегодня хочу поговорить о том, как ускорить приложение через конфигурирование PHP-FPM.
Сейчас самый популярный (из тех с которыми я сталкивался) стек на котором поднимается PHP приложение это веб сервер nginx и процесс-менеджер php-fpm.
Я хочу поднять простое приложение с Laravel проектом, которое устанавливается со всеми параметрами по умолчанию. Попробуем это приложение нагрузить пользователями с помощью простого Javascript скрипта и посмотрим как ему удастся справиться с нагрузкой и как мы можем повысить обрабатываемую нагрузку только конфигурированием php-fpm. В конце статьи можно будет найти ссылку на GitHub и попробовать своими руками.
Для начала посмотрим на стандартную конфигурацию php-fpm и попытаемся понять где могут быть проблемы в производительности с коробки.
Итак, у меня есть простое приложение на PHP с NGINX и PHP-FPM предустановленными в стандартных конфигурациях и маршрут Laravel.
Маршрут симулирует нагрузку через команду засыпания на одну секунду и возвращает простой json ответ.
Так же у меня есть Javascript файл который производит запрос на наш роут. Запускать его мы будем с помощью нагрузочной утилиты k6.
Для того чтобы провести нагрузочное тестирование давайте запустим утилиту k6 с пятью VU (virtual users)
k6 run —vus 5 —duration 30s script.js
Как видим в строке http_req_duration avg (среднее по всем показателям значение) равно 1.77 сек. Это сама нагрузка 1 секунда + время прохода запроса по сети и работа фреймворка.
Давайте проведём еще один такой же тест но на 10и пользователях
k6 run —vus 10 —duration 30s script.js
Как видим время возросло почти в два раза.
Давайте проведём еще один тест и будем разбираться в чём же дело.
На этот раз попробуем нагрузить сразу 50ью пользователями наше приложение.
k6 run —vus 50 —duration 30s script.js
Как видим результат стал совсем грустным. В среднем клиенту приходится ждать ответа от сервера 15.48 секунд. Давайте разбираться в чём дело.
Для начала давайте узнаем какая сейчас конфигурация php-fpm. Сделать это можно с помощью команды php-fpm -tt
Эта команда выведет все параметры php-fpm, самые важные параметры я обвел рамкой.
Самый важный параметр — это pm.max_children он равен сейчас 5. Этот параметр сообщает нашему php-fpm сколько он может максимально запустить дочерних процессов (обработчиков) запросов. Иными словами сколько параллельно процессов будет обрабатывать входящую нагрузку.
Для лучшей наглядности я нарисовал небольшую схему.
Когда в наше приложение одномоментно приходит 50 клиентов они сначала обращаются в наш NGINX, он является просто прокси сервером и пробрасывает запросы сквозь себя на PHP-FPM (за исключением запросов за статическими ресурсами/файлами) и дальше PHP-FPM пытается обработать все запросы с помощью своих процессов (воркеров). Если же ситуация как у нас, когда PHP-FPM располагает только пятью воркерами, то первые 5 клиентов обрабатываются, а остальные 45 становятся в очередь и ждут, когда первые 5 обработаются. Как только первые 5 отработали, следующие 5 зашли на их место и оставшиеся 40 ждут в очереди.
На этом этапе появляется две проблемы. Первая — мы заставляем таким образом ждать клиентов ответа, вторая — если время ожидания будет выше стандартного для NGINX в параметре fastcgi_read_timeout (стандартное 30 секунд) то мы можем получить 504 ошибку от NGINX. Вторую проблему мы можем исправить увеличив время ожидания, но это не спасет нас от первой проблемы.
Логичное решение проблемы — просто добавить воркеров для PHP-FPM и это вполне адекватная мысль, но стоит позаботиться о том, чтобы добавить достаточно воркеров и не добавить лишних воркеров, которые займут всю операционную память.
Давайте вернёмся к нашим конфигурационным параметрам и постараемся сделать правильную настройку.
Итак, нас интересуют следующие параметры:
pm = dynamic — php-fpm сам контролирует количество запущенных воркеров, при указанном параметре dynamic php-fpm будет в зависимости от нагрузки добавлять или удалять воркеры. Так же в этом параметре может быть значение static в таком случае количество воркеров будет статическим.
pm.max_children — максимальное количество процессов единовременно работающих. Часто это значение ставится в количестве 4 * на количество CPU. Для того чтобы узнать количество CPU можно воспользоваться командой lscpu.
Более правильно будет еще проверить количество свободной памяти, можно сделать это командой free -hl
Обязательно нужно понимать сколько памяти занимает один воркер.
Это можно сделать с помощью команды htop и посмотреть среднее количество памяти которое занимают воркеры php-fpm
pm.min_spare_servers — минимальное количество процессов в состоянии ожидания. Это количество нужно как резервное в случае внезапного появления нового количества клиентов. Чтобы клиенты не ждали пока новые процессы создадутся резервные процессы подхватят внезапную нагрузку. Значение обычно ставится в 2 * на количество CPU.
pm.max_spare_servers — максимальное количество процессов в состоянии ожидания. В случае если нет нагрузки на приложение php-fpm удалит лишние процессы с целью сохранить оперативную память.
Хорошо, давайте сконфигурируем наш PHP-FPM.
Для начала найдем где находится файл конфигурации с помощью команды
И повторим нагрузочное тестирование с 50ью пользователями.
Как видите результат нагрузки средний 1.6 секунд. Примерно как и был в первом тесте, с пятью пользователями.
Так же еще можно посмотреть как отрабатывает php-fpm при установке pm стратегии в dynamic. Если вы запустите htop, то увидите стартовое количество воркеров
и если запустите тест, то постепенно количество воркеров сначала увеличится до максимально доступного
и после окончания теста снизится до начального.