pm.max_children — параметр PHP-FPM, від якого найчастіше залежить, впаде сайт під навантаженням у 502 Bad Gateway чи витримає його. Надто низьке значення забиває сервер черги запитів, надто високе — обрушує його через дефіцит пам'яті (OOM). Нижче — чесна формула розрахунку і те, чого вона не передбачає без заміру на реальному навантаженні.
З чого складається бюджет пам'яті для PHP-FPM
Перш ніж рахувати кількість процесів, важливо зрозуміти, скільки пам'яті на сервері фізично вільно під PHP-FPM. Із загального обсягу RAM віднімається те, що вже зайняте операційною системою, MySQL чи іншою СУБД, Redis і Nginx. Залишок і є бюджет, який можна віддати воркерам PHP-FPM.
Наприклад, на VPS із 8 GB RAM, якщо під систему і MySQL зарезервовано 3 GB, під PHP-FPM залишається приблизно 5 GB (5120 MB). Окремий ліміт пам'яті одного процесу PHP — тема статті про memory_limit і upload_max_filesize, а тут рахується сукупний бюджет на весь пул воркерів.
Як виміряти реальний розмір одного процесу
Теоретичні розрахунки марні без заміру фактичного споживання пам'яті воркерами. Правильний спосіб — подивитися RSS (resident set size) вже запущених процесів php-fpm на сервері під звичайним, а не піковим навантаженням.
Команда ps -o rss= -C php-fpm8.3 | awk '{sum+=$1} END {print sum/NR/1024" MB"}' виводить середній розмір процесу в мегабайтах. Знімати значення варто кілька разів протягом дня: після прогріву OPcache і під різним навантаженням, бо розмір процесу зростає з підключенням нових файлів і розширень.
Формула розрахунку pm.max_children
У загальному вигляді формула така: pm.max_children дорівнює обсягу пам'яті, доступної PHP-FPM, поділеному на середній розмір одного процесу. Результат — верхня межа, а не цільове значення: окремі процеси розбухають під час обробки важких запитів, тому варто залишити запас 20-30% від розрахунку. Детальний розбір режимів pm та інших параметрів пулу — у статті про пули й воркери PHP-FPM.
- Налаштування opcache.memory_consumption і кількість закешованих файлів
- Важкі розширення — imagick, intl, gd — додають пам'ять кожному процесу
- Розмір бутстрапа фреймворка: Laravel і Symfony завантажують більше класів, ніж голий PHP
- Драйвер зберігання сесій — файлові сесії легші, ніж сесії в пам'яті процесу
- Обсяг автозавантаження Composer — чим більше залежностей, тим важчий стартовий код
Приклад розрахунку для кількох конфігурацій
Таблиця нижче показує лише арифметику ділення, а не результат заміру на реальному сайті. Середній розмір процесу і доступну пам'ять варто брати зі свого сервера, інакше числа будуть безглузді.
| RAM для PHP-FPM | Середній розмір процесу | pm.max_children (округлено) |
|---|---|---|
| 1024 MB | 50 MB | 20 |
| 2048 MB | 60 MB | 34 |
| 4096 MB | 70 MB | 58 |
| 5120 MB | 60 MB | 85 |
Підсумкові параметри пулу
Від pm.max_children залежать і інші параметри режиму dynamic: pm.start_servers зазвичай беруть як 25-30% від max_children, pm.min_spare_servers — приблизно половину від start_servers, а pm.max_spare_servers — у півтора раза більше start_servers. Як ці параметри передаються в Nginx через fastcgi_pass, описано в статті про зв'язку Nginx і PHP-FPM.
pm = dynamic
pm.max_children = 70
pm.start_servers = 20
pm.min_spare_servers = 10
pm.max_spare_servers = 30
pm.max_requests = 500Що відбувається при неправильному значенні
Надто низьке значення pm.max_children означає, що під час стрибка трафіку нові запити стають у черзі до сокета PHP-FPM і чекають вільного процесу; якщо очікування перевищує таймаут Nginx, клієнт отримує 502 чи 504. Це схоже на дефіцит процесів, але причина в конфігурації, а не в коді.
Надто високе значення небезпечніше: якщо кожен процес у піку важить 80-100 MB, а запущено їх більше, ніж дозволяє фізична пам'ять, сервер іде в swap або ядро вбиває процеси через OOM killer. Відновлення після OOM займає більше часу, ніж коротка черга запитів.
Часті питання
Чи можна поставити pm.max_children із великим запасом, на всякий випадок?
Ні: зайві процеси не прискорюють обробку запитів, вони просто займають пам'ять, яка не використовується більшу частину часу, і підвищують ризик OOM у момент пікового трафіку.
Як часто варто перераховувати значення?
Перерахунок варто робити після зміни обсягу RAM, після масштабного оновлення фреймворка чи залежностей і після помітної зміни трафіку. Поточне завантаження пулу зручно дивитися через pm.status_path.
Сайт все одно віддає 502 після налаштування pm.max_children, що перевірити?
Спочатку варто виключити повільні запити до бази даних і зовнішніх API: якщо кожен запит висить по 10-15 секунд, зростання кількості процесів лише відкладе проблему, а не вирішить її.