Настройка PHP-FPM для WordPress: Оптимизация пула процессов

Если вы уже настроили Nginx reverse proxy и увеличили memory_limit в PHP, но сайт всё ещё тормозит под нагрузкой — проблема скорее всего в PHP-FPM. Это не просто «ещё один способ запустить PHP», а мощный менеджер процессов, который при правильной настройке выдерживает в 3-5 раз большую нагрузку по сравнению со стандартным mod_php.

В этом руководстве мы разберём архитектуру PHP-FPM, настроим пул процессов под разные сценарии нагрузки и научимся мониторить производительность в реальном времени.

Что такое PHP-FPM и почему это важно

PHP-FPM (FastCGI Process Manager) — это альтернативная реализация PHP FastCGI с дополнительными возможностями для высоконагруженных сайтов. В отличие от mod_php, который создаёт новый процесс PHP для каждого запроса, PHP-FPM держит пул готовых процессов, что eliminates overhead на запуск интерпретатора.

Архитектура PHP-FPM:

  • Master process — управляет пулом, слушает сокеты, создаёт/уничтожает worker’ы
  • Worker processes — обрабатывают PHP-запросы от Nginx
  • Socket — точка связи между Nginx и PHP-FPM (Unix socket или TCP)

Для WordPress это критично: каждый запрос к сайту (даже закэшированный) проходит через PHP-FPM для проверки авторизации, загрузки плагинов и генерации HTML. Оптимизированный пул = быстрый отклик.

Шаг 1: Базовая настройка пула процессов

Конфигурация PHP-FPM находится в /etc/php/8.2/fpm/pool.d/www.conf (для Ubuntu/Debian с PHP 8.2). Открываем файл:

sudo nano /etc/php/8.2/fpm/pool.d/www.conf

Находим секцию с настройками пула и настраиваем под наш сервер:

; Базовые настройки пула
user = www-data
group = www-data
listen = /run/php/php8.2-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

; Настройки процессов (формулы ниже)
pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 500

Шаг 2: Выбор стратегии управления процессами

Параметр pm определяет, как PHP-FPM управляет worker’ами. Есть три режима:

Dynamic (по умолчанию)

Количество процессов меняется динамически в зависимости от нагрузки. Подходит для большинства сайтов.

pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20

Static

Фиксированное количество процессов. Максимальная производительность, но требует точного расчёта. Рекомендуется для высоконагруженных проектов с стабильным трафиком.

pm = static
pm.max_children = 30

Ondemand

Процессы создаются по запросу и уничтожаются после простоя. Экономит память, но добавляет задержку при первом запросе. Подходит для сайтов с низкой посещаемостью.

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

Шаг 3: Расчёт оптимального количества процессов

Главная формула для расчёта pm.max_children:

pm.max_children = (Общая RAM - RAM для системы - RAM для MySQL) / RAM на один процесс PHP

Пример расчёта для VPS с 4GB RAM:

  • Всего RAM: 4096 MB
  • Система + Nginx: 512 MB
  • MySQL/MariaDB: 512 MB
  • Redis: 256 MB
  • Доступно для PHP: 4096 — 512 — 512 — 256 = 2816 MB
  • Среднее потребление одного процесса WordPress: 64-128 MB
  • pm.max_children = 2816 / 96 ≈ 29 процессов

Как узнать реальное потребление процесса PHP:

# Смотрим потребление всех PHP-FPM процессов
ps aux | grep php-fpm | awk '{print $6}' | paste -sd+ | bc

# Или через top
top -c | grep php-fpm

Шаг 4: Настройка для разных сценариев

Сценарий 1: Небольшой блог (до 1000 посетителей/день)

pm = dynamic
pm.max_children = 10
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 5
pm.max_requests = 1000

Сценарий 2: Средний сайт (1000-10000 посетителей/день)

pm = dynamic
pm.max_children = 30
pm.start_servers = 8
pm.min_spare_servers = 4
pm.max_spare_servers = 12
pm.max_requests = 500

Сценарий 3: Высоконагруженный проект (10000+ посетителей/день)

pm = static
pm.max_children = 40
pm.max_requests = 1000

Шаг 5: Дополнительные параметры производительности

Добавляем эти настройки в конец секции пула:

; Лимит времени выполнения (секунды)
request_terminate_timeout = 300

; Лимит памяти на процесс (должен совпадать с memory_limit в php.ini)
php_admin_value[memory_limit] = 256M

; Лог медленных запросов (для отладки)
slowlog = /var/log/php-fpm/www-slow.log
request_slowlog_timeout = 5s

; Ограничение ресурсов процесса
rlimit_files = 1024
rlimit_core = 0

; Catch workers output (для отладки)
catch_workers_output = yes
php_admin_flag[log_errors] = on

Шаг 6: Настройка Unix socket vs TCP

По умолчанию PHP-FPM использует Unix socket — это быстрее TCP на 10-15%. Но если Nginx и PHP-FPM работают на разных серверах, нужен TCP.

Unix socket (рекомендуется для одного сервера):

listen = /run/php/php8.2-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

TCP (для распределённых систем):

listen = 127.0.0.1:9000
listen.allowed_clients = 127.0.0.1

В конфиге Nginx меняем accordingly:

# Для Unix socket
fastcgi_pass unix:/run/php/php8.2-fpm.sock;

# Для TCP
fastcgi_pass 127.0.0.1:9000;

Шаг 7: Мониторинг производительности

Включаем статусную страницу PHP-FPM для мониторинга:

; В конце www.conf добавляем
pm.status_path = /status
ping.path = /ping

В конфиге Nginx добавляем блок для доступа к статусу:

location ~ ^/(status|ping)$ {
    include fastcgi_params;
    fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    
    # Ограничиваем доступ по IP
    allow 127.0.0.1;
    allow 192.168.1.0/24;
    deny all;
}

Теперь можно мониторить через:

# Базовая информация
curl http://127.0.0.1/status

# Подробная информация (JSON)
curl http://127.0.0.1/status?json

# Полная информация
curl http://127.0.0.1/status?full

Ключевые метрики для мониторинга:

  • active processes — количество активных worker’ов (должно быть < max_children)
  • idle processes — свободные worker’ы (должно быть > min_spare_servers)
  • slow requests — медленные запросы (идеально 0)
  • max active processes — пиковая нагрузка (если = max_children, нужно увеличивать)

Шаг 8: Интеграция с systemd для автозапуска

Убеждаемся, что PHP-FPM запускается автоматически и перезапускается при сбоях:

# Включаем автозапуск
sudo systemctl enable php8.2-fpm

# Настраиваем автоперезапуск при сбоях
sudo systemctl edit php8.2-fpm

Добавляем:

[Service]
Restart=always
RestartSec=3
StartLimitInterval=60
StartLimitBurst=3

Чек-лист оптимизации PHP-FPM

  • ✅ Выбрана правильная стратегия (dynamic/static/ondemand)
  • ✅ Рассчитано оптимальное количество процессов по формуле
  • ✅ Настроены spare servers для динамического режима
  • ✅ Установлен pm.max_requests для предотвращения утечек памяти
  • ✅ Включён slowlog для отладки медленных запросов
  • ✅ Настроен мониторинг через status page
  • ✅ Проверены права на socket (для Unix socket)
  • ✅ Настроен автозапуск и автоперезапуск через systemd

Что делать, если проблемы не решаются?

502 Bad Gateway от Nginx

Это значит, что Nginx не может достучаться до PHP-FPM. Проверяем:

  • Работает ли PHP-FPM: sudo systemctl status php8.2-fpm
  • Совпадает ли путь к socket в конфиге Nginx и PHP-FPM
  • Права на socket: ls -la /run/php/php8.2-fpm.sock (должен быть www-data)
  • Не превышен ли лимит процессов: ps aux | grep php-fpm | wc -l

Процессы постоянно перезапускаются

Если в логах видите «WARNING: [pool www] server reached pm.max_children setting», значит не хватает worker’ов. Увеличиваем pm.max_children по формуле из Шага 3.

Высокое потребление памяти

Если PHP-FPM ест всю RAM, возможно:

  • Слишком большой pm.max_children — уменьшаем
  • Утечка памяти в плагинах — включаем pm.max_requests = 500 для периодического перезапуска worker’ов
  • Слишком высокий memory_limit — проверяем реальные потребности через Redis Object Cache

Медленные запросы

Если slowlog показывает запросы > 5 секунд:

  • Проверяем медленные SQL-запросы через Query Monitor
  • Оптимизируем тяжёлые плагины
  • Увеличиваем request_terminate_timeout (но это костыль, лучше найти причину)

Best practices для продакшна

  • Используйте static режим для стабильной высокой нагрузки
  • Устанавливайте pm.max_requests между 500-1000 для предотвращения утечек
  • Мониторьте slowlog регулярно — это индикатор проблем
  • Настройте алерты на max active processes = max_children
  • Используйте Unix socket вместо TCP, если всё на одном сервере
  • Регулярно пересчитывайте pm.max_children при изменении нагрузки

Правильно настроенный PHP-FPM — это фундамент производительности WordPress. Потратив 30 минут на настройку, вы получите стабильный сайт, который выдерживает пиковые нагрузки без падений и тормозов.