С момента установки хостинг-панели ISP CP Omega не трогал настройки mod_fcgid, через который веб-сервер работал с PHP. Уже сменилось несколько серверов, уже даже избавился от хостинг-панели, а софт уехал на VPS’ку, а конфиги так и кочевали с одного места на другое. Однако на VPS’ке не так много памяти, поэтому решил оптимизировать один из самых ресурсоемких компонентов – PHP.
Собственно, до недавнего времени на нехватку памяти особо не жаловался. Судя по графикам munin’а, в начале мая резко выросло число процессов php-cgi – как раз тогда сделал миграцию веб-части с Debian 10 на Debian 11. Спустя месяц сложно сказать, что именно поменялось, однако до того обычно висело около 15 процессов, стало – в среднем 35. А в моменты нагрузки и того больше и память начинала заканчиваться.
В php-cgi-стартерах (которые в свое время создала хостинг-панель) есть переменная PHP_FCGI_CHILDREN; значение со времен панели стояло 2. “Наощупь” немного поигрался со значением, но непонятно было, стоит ли вообще его менять и в каких пропорциях с остальными параметрами. Пока не нашел это:
- Первая статья. Тут, правда, речь про использование с акселераторами, но заставило задуматься.
- А вот на форуме одной из хостинг-панелей с отсылкой к документации Апача.
- Ну и, собственно, ключевой момент из упомянутой документации: “PHP child process management (
PHP_FCGI_CHILDREN
) should always be disabled with mod_fcgid, which will only route one request at a time to application processes it has spawned; thus, any child processes created by PHP will not be used effectively. (Additionally, the PHP child processes may not be terminated properly.) By default, and with the environment variable settingPHP_FCGI_CHILDREN=0
, PHP child process management is disabled”.
После этого уже поставил везде переменную в ноль и начал изучать остальные опции, теперь уже в /etc/apache2/mods-available/fcgid.conf. Основное, что сначала скорректировал – MaxProcessCount – в общем-то, в итоге вернул его в значение до начала всех экспериментов. А по остальным опциям понятное описание на русском нашел здесь. Сайт, правда, в Чебурнете, так что продублирую тут:
IdleTimeout — это время бездействия запущенного процесса перед тем, как он будет убит.
IdleScanInterval — интервал сканирования процессов на бездействие.
BusyTimeout — время занятости процесса одним запросом до убиения (если процесс занят больше указанного одним запросом — он будет убит, как зависший). BusyScanInterval — интервал сканирования на зависы.
IPCConnectTimeout — время ожидания соединения с выбранным не занятым процессом. Если соединиться за указанное время не удалось — выбранный процесс убивается, как подвисший, а клиенту возвращается 500.
IPCCommTimeout — время ожидания первой порции данных (ответа) от процесса. Если ответа нету — также KILL+500.
SocketPath и SharememPath — это служебные пути. Первый путь — к каталогу, в котором будут создаваться сокеты для связи с процессами FastCGI. Второй — к файлу разделяемой памяти диспетчера FastCGI, который будет создан во время работы. Каталог должен существовать.
MaxProcessCount, DefaultMinClassProcessCount, DefaultMaxClassProcessCount — это управление нагрузкой. Первое — максимальное число всех процессов на весь сервер (все виртуалхосты). Второе — минимум процессов для одного приложения (например — PHP), которое будет поддерживаться. Тут я ставлю 0 — т.е. если вхост вообще не активен, пусть лучше убьются все, и не занимают бестолку память. Третье — максимум процессов для одного приложения.
MaxRequestsPerProcess. Количество запросов, после которого процесс будет убит и перезапущен. Т.е. обработали 200 запросов — будьте добры в рестарт. Меньшее число повышает надежность, большее — производительность. PHP со значениями 500 и выше в стандартной конфигурации может и не работать.
PHP_Fix_Pathinfo_Enable — тут единичка, потому что работаем корректно — надо давать PHP нормальные скриптовые пути. Не забудьте в php.ini поставить cgi.fix_pathinfo = 1.
Так как “классов” приложений у меня только 1 – PHP, то DefaultMaxClassProcessCount = MaxProcessCount = 30 (исходя из того, что это более-менее нормально влазит в память и этого должно более чем хватать). Насчет DefaultMinClassProcessCount – не согласен, пусть висит хоть 1 для минимизации времени запуска. Правда, это 1 на весь класс, без конкретизации, к какому сайту он относится. В принципе, можно поставить чуть выше – 4-5, например.
Ну и еще из полезного (с той же странички доков Апача):
FcgidMaxRequestsPerProcess should be <= PHP_FCGI_MAX_REQUESTS
Интуитивно вроде понимаю, но переменная у меня все равно не используется, так что не вникал.
На сейчас число процессов PHP держится даже ниже, чем было до обновления – на уровне 10-11, зато наконец-то есть вменяемое управление ими.