Урок 02

Настройка пулов PHP-FPM

Что такое пул

Пул — набор процессов PHP, готовых обрабатывать запросы. Один PHP-FPM может держать несколько пулов — для разных сайтов или с разными настройками.

По умолчанию — один пул www.

Файл пула

/etc/php/8.5/fpm/pool.d/www.conf:

[www]
user = www-data
group = www-data

listen = /var/run/php/php8.5-fpm.sock
listen.owner = www-data
listen.group = www-data

pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
pm.max_requests = 500

Ключевые параметры

user и group

user = www-data
group = www-data

От кого работают процессы.

Важно: файлы Laravel должны принадлежать www-data. Иначе storage/ не пишется, права не читаются.

listen

listen = /var/run/php/php8.5-fpm.sock

Unix-сокет или TCP-порт (127.0.0.1:9000).

Сокет быстрее (нет сетевого стека), но только локально.

TCP — если PHP-FPM на другом сервере.

pm — стратегия управления

pm = dynamic — процессы создаются/убиваются по нагрузке. Стандарт.

pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6

pm = static — фиксированное число процессов. Быстрее, но жрёт RAM постоянно.

pm = static
pm.max_children = 20

pm = ondemand — процессы создаются только при запросе. Экономит RAM, но медленный старт.

pm = ondemand
pm.process_idle_timeout = 10s

Когда что:

  • Много RAM, стабильная нагрузка → static
  • Средний сервер → dynamic
  • Мало RAM, редкие запросы → ondemand

pm.max_children

Максимум процессов. Критичный параметр.

Формула:

max_children = доступная_RAM / память_одного_процесса

Сколько памяти ест процесс Laravel:

ps -ylC php-fpm8.5 --sort:rss | awk '{sum+=$8; count++} END {print "Средний: " sum/count/1024 " MB"}'

Обычно 30-60 МБ на процесс Laravel. С учётом кешей — до 80 МБ.

Пример: сервер 2 ГБ RAM, отдаём под PHP-FPM 1.5 ГБ, процесс по 60 МБ:

1500 / 60 = 25 процессов

Ставь 20-25 — с запасом на ОС, БД, Nginx.

pm.start_servers

Сколько процессов при старте:

pm.start_servers = 4

Формула: max_children / 4 или max_children / 2.

pm.min_spare_servers

Минимум свободных процессов. Если меньше — создаются новые.

pm.min_spare_servers = 2

pm.max_spare_servers

Максимум свободных процессов. Если больше — убиваются лишние.

pm.max_spare_servers = 6

pm.max_requests

После скольких запросов процесс перезапускается.

pm.max_requests = 500

Защита от утечек памяти. Laravel может течь — после 500 запросов процесс пересоздаётся.

Для прода: 500-1000. Для тяжелых приложений: 200-500.

Реальный расчёт

Сервер: 4 vCPU, 4 ГБ RAM.

Что отдать:

  • ОС: 500 МБ
  • PostgreSQL: 1 ГБ
  • Nginx: 100 МБ
  • PHP-FPM: 2 ГБ

Процесс Laravel: 60 МБ.

max_children:

2000 / 60 = 33

Ставь 25 — с запасом.

Конфиг:

pm = dynamic
pm.max_children = 25
pm.start_servers = 6
pm.min_spare_servers = 4
pm.max_spare_servers = 10
pm.max_requests = 500

Несколько пулов

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

/etc/php/8.5/fpm/pool.d/skills.conf:

[skills]
user = www-data
group = www-data
listen = /var/run/php/php8.5-fpm-skills.sock

pm = dynamic
pm.max_children = 30
pm.start_servers = 6
pm.max_requests = 500

/etc/php/8.5/fpm/pool.d/nobleweb.conf:

[nobleweb]
user = www-data
group = www-data
listen = /var/run/php/php8.5-fpm-nobleweb.sock

pm = ondemand
pm.max_children = 5
pm.process_idle_timeout = 10s

В Nginx — свой fastcgi_pass для каждого сайта.

Плюс: сайты изолированы — падение одного не затрагивает другой.

Slow log

Медленные запросы (> N секунд):

request_slowlog_timeout = 5s
slowlog = /var/log/php8.5-fpm-slow.log

Что попадает: PHP-стек вызовов, где задержка.

Смотреть:

tail -f /var/log/php8.5-fpm-slow.log

Огромная польза — сразу видно, где тормозит приложение.

Пинг-страница

Для проверки пула:

В www.conf:

ping.path = /ping
ping.response = pong

Проверка:

cgi-fcgi -bind -connect /var/run/php/php8.5-fpm.sock

Или через curl к Nginx, если настроен роут.

Status-страница

Мониторинг состояния пула:

В www.conf:

pm.status_path = /status

В Nginx:

location ~ ^/(status|ping)$ {
    fastcgi_pass unix:/var/run/php/php8.5-fpm.sock;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    allow 127.0.0.1;
    deny all;
}

Проверка:

curl http://127.0.0.1/status

Вывод:

pool:                 www
process manager:      dynamic
accepted conn:        12345
pool:                 www
idle processes:       5
active processes:     3
total processes:      8
max active processes: 15
max children reached: 0

Что важно:

  • active processes — сколько сейчас работают
  • idle processes — сколько свободны
  • max children reached — если > 0, max_children не хватило — увеличивай

Мониторинг

Процессы:

ps aux | grep php-fpm | wc -l

Память каждого:

ps -ylC php-fpm8.5 --sort:rss

Кто сколько ест:

ps aux | grep php-fpm | awk '{sum+=$6} END {print sum/1024 " MB"}'

Перезагрузка конфига

sudo systemctl reload php8.5-fpm

⚠️ reload не пересоздаёт процессы — только перечитывает конфиг. Для применения max_children нужно:

sudo systemctl restart php8.5-fpm

На проде — делай в низкую нагрузку или через graceful reload (по одному процессу).

Частые ошибки

1. 502 Bad Gateway — сокет не совпадает. Проверь listen в пуле и fastcgi_pass в Nginx.

2. max children reached — увеличь pm.max_children.

3. Процессов больше, чем задумано — min_spare_servers и start_servers тоже регулируют.

4. Память кончается — уменьши max_children.

Итог

Правила настройки:

  • max_children — по формуле RAM / 60 МБ
  • pm = dynamic — для средних серверов
  • max_requests = 500 — защита от утечек
  • slow log — обязательно
  • status page — для мониторинга

Дальше — OPcache.