WebSite

FPM (Менеджер процессов FastCGI) является альтернативной реализацией PHP FastCGI с несколькими дополнительными возможностями обычно используемыми для высоконагруженных сайтов.

Автор PHP-FPM - Андрей Нигматулин.

  • продвинутое управление процессами с корректной (graceful) процедурой остановки и запуска;
  • возможность запуска воркеров с различными uid/gid/chroot-окружением, а также запуска на различных портах с использованием разных php.ini (замещение safe_mode);
  • логирование стандартных потоков вывода (stdout) и ошибок (stderr);
  • аварийный перезапуск в случае внезапного разрушения opcode-кэша (OPcache улучшает производительность PHP путём сохранения скомпилированного байт-кода скриптов в разделяемой памяти, тем самым избавляя PHP от необходимости загружать и анализировать скрипты при каждом запросе);
  • поддержка ускоренной загрузки (accelerated upload);
  • "slowlog" - логирование необычно медленно выполняющихся скриптов (не только их имена, но также и их трассировки (процесс пошагового выполнения программы). Это достигается с помощью ptrace и других подобных утилит для чтения данных исполнения удаленных процессов);
  • Динамическое/статическое порождение дочерних процессов;
  • Базовая информация о статусе SAPI (Server Application Programming Interface — программный интерфейс для взаимодействия приложений с веб-сервером);
  • Конфигурационный файл, основанный на php.ini.

CGI

Common Gateway Interface, "общий интерфейс шлюза" — это стандарт, который описывает, как веб-сервер должен запускать прикладные программы (скрипты), как должен передавать им параметры HTTP-запроса, как программы должны передавать результаты своей работы веб-серверу. Прикладную программу взаимодействующую с веб-сервером по протоколу CGI принято называть шлюзом, хотя более распространено название CGI-скрипт или CGI-программа.

В качестве CGI-программ могут использоваться программы/скрипты написанные на любых языках программирования, как на компилируемых, так и на скриптовых, и даже на shell.

CGI-скрипты были популярны до того, как для веб-разработки стали преимущественно использовать PHP. Хотя сам PHP интерпретатор позволяет работать в режиме CGI.

Основной момент: "CGI" это не язык программирования и не отдельная программа! Это просто протокол (стандарт, спецификация, соглашение, набор правил).

FastCGI

Дальнейшее развитие технологии CGI, является более производительным и безопасным, снимает множество ограничений CGI-программ.

FastCGI программа работает следующим образом: программа единожды загружается в память в качестве демона (независимо от HTTP-сервера), а затем входит в цикл обработки запросов от HTTP-сервера. Один и тот же процесс обрабатывает несколько различных запросов один за другим, что отличается от работы в CGI-режиме, когда на каждый запрос создается отдельный процесс, "умирающий" после окончания обработки.

Написание FastCGI программ-демонов сложнее чем CGI, нужны дополнительные библиотеки, зависящие от языка.

Опять же, сама аббревиатура FastCGI это не язык программирования и не отдельная программа, это как и в случае CGI — просто спецификация.

PHP в режиме CGI

PHP в режиме CGI это самый старый способ выполнения php-скриптов веб-сервером. Режим доступен по умолчанию, однако может быть отключён при компиляции.

Для Apache нужен модуль mod_cgi (поставляется вместе с Apache). Nginx из коробки поддержки не имеет, хотя существуют дополнительные инструменты.

В данный момент режим используется редко в силу малой производительности.

PHP в режиме FastCGI

Помимо CGI режима, PHP из коробки умеет работать и в FastCGI режиме (с версии 5.3 даже в двух FastCGI режимах). Режим включается флагом при компиляции интерпретатора, флаг зависит от версии PHP.

Для работы с Apache нужен модуль mod_fcgid или mod_fastcgi, либо связка из mod_proxy_fcgi + PHP-FPM.

Nginx умеет работать с FastCGI приложениями из коробки, но именно для PHP дополнительно нужен PHP-FPM.

Следует помнить, что при работе PHP в режиме FastCGI в памяти висит сам php интерпретатор, а не какой-то конкретный php-скрипт.

PHP-FPM

FastCGI Process Manager, "Менеджер процессов FastCGI". Это альтернативная реализация FastCGI режима в PHP с несколь­кими допол­ни­тель­ными воз­мож­но­стя­ми, кото­рые обычно исполь­зу­ются для высо­ко­на­гру­жен­ных сайтов.

Изначально PHP-FPM представлял из себя набор патчей от Андрея Нигматулина, которые устраняли ряд проблем, мешающих полноценно использовать PHP в режиме FastCGI. С версии PHP 5.3 набор патчей включён в ядро, а дополнительные возможности PHP-FPM включаются флагом при компиляции.

PHP-FPM используется в основном в связке с Nginx, без установки Apache.

mod_php

Это модуль для Apache, позволяющий ему выполнять php скрипты. Является наверно самым популярным и простым способом подружить Apache и PHP. Модуль не использует ни CGI, ни FastCGI. Есть свои минусы — скрипты работают под пользователем веб-сервера, невозможно использовать больше одной версии PHP.

OpCache

Как обычно выполняется PHP скрипт? PHP открывает файл с кодом, компилирует его, затем выполняет. Поскольку файлов может быть много, процесс их открытия, чтения и компиляции может отнимать кучу ресурсов. Если файлы не меняются, то постоянную компиляцию можно и не делать. Лучше сделать ее один раз и закэшировать результат.

Именно это и делает модуль opCache. Результат первой компиляции будет сохранен в кэш, с которым и будет работать PHP. Таким образом это ускорит выполнение за счет отсутствия тяжелого процесса компиляции. Когда файлы изменятся, модуль сам сбросит кэш и обеспечит перекомпиляцию. Короче, этот модуль делает очень полезную экономию ресурсов. И это без необходимости его настраивать.

В версии PHP5.5+ этот модуль поставляется в стандартной сборке. В предыдущих версиях модуль нужно устанавливать самостоятельно. Проверить наличие можно так:

php -i | grep opcache

Пустой вывод будет означать, что модуля нет.

SAPI

SAPI - Server Application Programming Interface. В php есть несколько таких API для разных вариантов его работы:

  • CLI SAPI - в качестве консольной команды `php` для запуска наших кронов и других cli-программ (Command Line Interface)
  • apxs2 SAPI - в качестве модуля к apache2
  • CGI SAPI - в качестве запускаемого на каждом запросе CGI (сейчас так почти никто не делает)
  • FPM SAPI - Fast Process Manager написанный для PHP разработчиками из комании Badoo и теперь поддерживаемый сообществом

Работа с FPM отличается от работы с Apache в первую очередь тем, что FPM - это только PHP. Это не веб-сервер, не что-то умное. Это наоборот - максимально простой, легкий и быстрый менеджер процессов для PHP. В отличие от апача он даже не использует http-протокол, а работает со специальным fastcgi-протоколом. В первую очередь FPM быстрее обрабатывает запросы благодаря его легковесности и простоте.

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

Нужно помнить, что независимо от того, какое SAPI вы используете, будь то модуль Apache, CGI или PHP-FPM - это не отнимает ни каких особенностей php:

  • Один процесс одновременно обрабатывает один запрос. Это абсолютно так же свойственно для PHP-FPM, как и для Apache.
  • Количество процессов определяет сколько одновременно может "висеть" запросов в обработке.
  • Точно также, как и Apache, FPM подвержен DoS-атакам путем "длительных запросов". Допустим у Вас на сервере работает не более 50-ти процессов PHP-FPM, а это значит, что если 50 пользователей одновременно начнут делать upload файла (пусть даже небольшого, но главное чтобы они делали это медленно) - пятьдесят первый пользователь получит ошибку 504, т.к. FPM не возьмет его запрос на обработку, пока не разберется с теми что у него уже есть.

Пулы php-fpm - позволяют запускать процессы php под разными пользователями, тем самым создавая более безопасную среду. Так же, каждому пулу можно выделять свои ресурсы и переопределять переменные php.ini. Например: Для production версии сайта - один пул, для development версии сайта - другой пул. Каждый пул работает или на отдельном порте, или на отдельном сокет файле. Как утверждают некоторые мануалы по оптимизации php-fpm - то для сайта с высокой нагрузкой разумней использовать несколько пулов.

FPM использует синтаксис php.ini для своего файла конфигурации php-fpm.conf и файлов конфигурации пулов.

php-fpm.conf

Список глобальных директив php-fpm.conf (Global Options):

  • pid string - Путь к PID файлу. По умолчанию: none.
  • error_log string - Путь к файлу журнала ошибок. По умолчанию: #INSTALL_PREFIX#/log/php-fpm.log. Если задано как "syslog", логирование будет производиться в syslogd, а не в локальный файл.
  • syslog.facility string - Используется для указания, какой тип программ будет логировать сообщения. По умолчанию: daemon.
  • syslog.ident string - Предшествует любому сообщению. Если у вас запущено несколько инстансов FPM, вы можете изменить значение по умолчанию на то, которое вам необходимо. По умолчанию: php-fpm.
  • log_level string - Уровень журналирования ошибок. Возможные значения: alert, error, warning, notice, debug. По умолчанию: notice.
  • emergency_restart_threshold int - При данном числе рабочих процессов, завершенных с SIGSEGV или SIGBUS за промежуток времени, установленный emergency_restart_interval FPM будет перезагружен. Значение 0 означает 'Off' (отключено). По умолчанию: 0 (Off).
  • emergency_restart_interval mixed - Интервал времени, используемый emergency_restart_interval, чтобы определить, когда FPM будет мягко перезагружен. Это полезно для избежания случайных повреждений общей памяти ускорителя (accelerator). Доступные единицы измерения: s(секунды), m(минуты), h(часы), или d(дни). Единица измерения по умолчанию: секунды. Значение по умолчанию: 0 (Off).
  • process_control_timeout mixed - Время, в течение которого дочерние процессы ждут ответа на сигналы мастер-процессу. Доступные единицы измерения: s(секунды), m(минуты), h(часы) или d(дни). Единица измерения по умолчанию: секунды. Значение по умолчанию: 0.
  • process.max int - Максимальное количество процессов, которое может породить FPM. Это сделано для того, чтобы контролировать глобальное количество процессов, когда используется большой пул динамического PM. Используйте с осторожность. По умолчанию: 0.
  • process.priority int - Указывает приоритет (Unix nice(2)) мастер-процесса (только если установлено). Принимает значения от -19(максимальный приоритет) до 20(минимальный.) По умолчанию: не установлено.
  • daemonize boolean - Запустить FPM в фоновом режиме. Установите значение 'no', чтобы запустить FPM в диспетчере для отладки. По умолчанию: yes.
  • rlimit_files int - Устанавливает rlimit открытых файловых дескрипторов для мастер-процесса.
  • rlimit_core int - Устанавливает rlimit максимального размера ядра для мастер-процесса. По умолчанию 0.
  • events.mechanism string - Указывает, какой событийный механизм будет использован FPM. Возможны такие варианты: select, pool, epoll, kqueue (*BSD), port (Solaris). По умолчанию: не установлено (автоопределение).
  • systemd_interval int - Если FPM собран с интеграцией с systemd, указывает интервал, в секундах, между оповещениями systemd о своем состоянии. Для отключения задайте 0. По умолчанию: 10.

Список директив для пулов (Pool Definitions):

  • prefix string - Задает префикс для вычисления пути.
  • user string - Unix-пользователь FPM-процессов. Этот параметр является обязательным.
  • group string - Unix-группа FPM-процессов. Если не установлен, группа по умолчанию равняется имени пользователя.
  • listen string - Адрес, который будет принимать FastCGI-запросы. Эта опция обязательна для каждого пула.
  • listen.backlog int - Устанавливает listen(2) backlog. Значение '-1' означает неограниченно. Значение по умолчанию: -1.
  • listen.owner string - Задает права для unix socket, если они используются. В Linux, чтобы разрешить соединения web серверу, должны быть установлены права на чтение/запись. Во многих основанных на BSD системах возможность соединения не зависит от прав доступа. Значение по умолчанию: используется пользователь и группа, от имени которого запущен сервер, установлен режим 0660.
  • listen.group string - Смотри listen.owner.
  • listen.mode string - Смотри listen.owner.
  • listen.acl_users string - Если поддерживается Список Контроля Доступа (ACL) POSIX, вы можете настроить его с помощью этой опции. Если задано, то listen.owner и listen.group будут проигнорированы. Значение задается списком имен, разделенных запятой. Доступно с PHP 5.6.5.
  • listen.acl_groups string - Смотри listen.acl_users. Значение задается списком имен групп, разделенных запятой. Доступно с PHP 5.6.5.
  • listen.allowed_clients string - Список IPv4 адресов FastCGI-клиентов, которые имеют право подключения. Эквивалент переменной окружения среды FCGI_WEB_SERVER_ADDRS в оригинальном PHP FastCGI (5.2.2+). Имеет смысл только с TCP-сокетом. Каждый адрес должен быть отделен запятой. Если оставить значение пустым, то соединения будут приниматься с любого IP. По умолчанию: any. Начиная с PHP 5.5.20 и 5.6.4, можно использовать IPv6.
  • process.priority int - Задает приоритет nice(2) для работающего процесса (только если задан). Значение от -19 (высший приоритет) до 20 (самый низкий). Значение по умолчанию: не задано.
  • pm string - Выбор того, как менеджер процессов будет контролировать создание дочерних процессов. Возможные значения: static, ondemand, dynamic. Этот параметр является обязательным.

    static - фиксированное число дочерних процессов (pm.max_children).

    dynamic - динамически изменяющееся число дочерних процессов, задается на основании следующих директив: pm.max_children, pm.start_servers, pm.min_spare_servers, pm.max_spare_servers.

    ondemand - число процессов, порождающихся по требованию (когда появляются запросы), в отличии от опции dynamic, когда стартует определенное количество процессов, равное pm.start_servers, вместе с запуском службы.
  • pm.max_children int - Число дочерних процессов, которые будут созданы, когда pm установлен в static, или же максимальное число процессов, которые будут созданы, когда pm установлен в dynamic. Этот параметр является обязательным. Этот параметр устанавливает ограничение на число одновременных запросов, которые будут обслуживаться.
  • pm.start_servers int - Число дочерних процессов, создаваемых при запуске. Используется, только когда pm установлен в dynamic. Значение по умолчанию: min_spare_servers + (max_spare_servers - min_spare_servers) / 2.
  • pm.min_spare_servers int - Желаемое минимальное число неактивных процессов сервера. Используется, только когда pm установлено в dynamic. Кроме того, это обязательный параметр в этом случае.
  • pm.max_spare_servers int - Желаемое максимальное число неактивных процессов сервера. Используется, только когда pm установлен в dynamic. Кроме того, это обязательный параметр в этом случае.
  • pm.process_idle_timeout mixed - Число секунд, по истечению которых простаивающий процесс будет завершен. Используется только если pm установлено как ondemand. Допустимые единицы: s(секунды)(по умолчанию), m(минуты), h(ours) или d(дни). По умолчанию: 10s.
  • pm.max_requests int - Число запросов дочернего процесса, после которого процесс будет перезапущен. Это полезно для избежания утечек памяти при использовании сторонних библиотек. Для бесконечной обработки запросов укажите '0'. Эквивалент PHP_FCGI_MAX_REQUESTS. Значение по умолчанию: 0.
  • pm.status_path string - Ссылка, по которой можно посмотреть страницу состояния FPM. Если значение не установлено, то страница статуса отображаться не будет. Значение по умолчанию: none.
  • ping.path string - Ссылка на ping-страницу мониторинга FPM. Если значение не установлено, ping-страница отображаться не будет. Может быть использовано для тестирования извне, чтобы убедиться, что FPM жив и реагирует. Обратите внимание, что значение должно начинаться с косой черты (/).
  • ping.response string - Эта директива может быть использована на настройки ответа на ping-запрос. Ответ формируется как text/plain с кодом ответа 200. Значение по умолчанию: pong.
  • access.log string - Лог-файл доступа. Значение по умолчанию: не установлено.
  • access.format string - Формат лог-файла доступа. Значение по умолчанию: "%R - %u %t \"%m %r\" %s".
  • slowlog string - Лог-файл для медленных запросов. Значение по умолчанию: #INSTALL_PREFIX#/log/php-fpm.log.slow.
  • request_slowlog_timeout mixed - Таймаут для обслуживания одного запроса, после чего PHP backtrace будет сохранен в файл 'slowlog'. Значение '0' означает 'выключено'. Доступные единицы измерения: s(секунды), m(минуты), h(часы) или d(дни). Значение по умолчанию: 0.
  • request_terminate_timeout mixed - Таймаут для обслуживания одного запроса, после чего рабочий процесс будет завершен. Этот вариант следует использовать, когда опция 'max_execution_time' в php.ini не останавливает выполнение скрипта по каким-то причинам. Значение '0' означает 'выключено'. Доступные единицы измерения: s(секунды), m(минуты), h(часы) или d(дни). Значение по умолчанию: 0.
  • rlimit_files int - Устанавливает лимит дескрипторов открытых файлов rlimit для дочерних процессов в этом пуле. Значение по умолчанию: определяется значением системы.
  • rlimit_core int - Устанавливает максимальное количество используемых ядер rlimit для дочерних процессов в этом пуле. Возможные значения: 'unlimited' или целое число большее или равное 0. Значение по умолчанию: определяется значением системы.
  • chroot string - Директория chroot окружения при старте. Это значение должно быть определено как абсолютный путь. Если значение не установлено, chroot не используется.
  • chdir string - Chdir изменяет текущую директорию при старте. Это значение должно быть определено как абсолютный путь. Значение по умолчанию: текущая директория или / при использовании chroot.
  • catch_workers_output boolean - Перенаправление STDOUT и STDERR рабочего процесса в главный лог ошибок. Если не установлен, STDOUT и STDERR будут перенаправлены в /dev/null в соответствии со спецификацией FastCGI. Значение по умолчанию: no.
  • clear_env boolean - Очищает окружение в "worker" процессах FPM.
  • security.limit_extensions string - Ограничивает расширения, которые FPM будет разбирать. Это позволит предотвратить ошибки на стороне веб-сервера. По умолчанию: .php.
  • Можно передать дополнительные переменные окружения и обновить настройки PHP для определенного пула. Для этого вам необходимо добавить следующие параметры в файл настройки пула.

    env[HOSTNAME] = $HOSTNAME
    env[PATH] = /usr/local/bin:/usr/bin:/bin
    env[TMP] = /tmp
    env[TMPDIR] = /tmp
    env[TEMP] = /tmp

    php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com
    php_flag[display_errors] = off
    php_admin_value[error_log] = /var/log/fpm-php.www.log
    php_admin_flag[log_errors] = on
    php_admin_value[memory_limit] = 32M

    PHP настройки, переданные через php_value или php_flag перезапишут их предыдущие значения. Пожалуйста, обратите внимание, что определения disable_functions или disable_classes не будут будут перезаписывать ранее определенные в php.ini значения, а добавят новые значения. Настройки, определенные через php_admin_value и php_admin_flag, не могут быть перезаписаны через ini_set().

Советы по настройке

Попробуем определить каким образом можно повысить производительность сервера приложений на базе php-fpm, а также сформировать чек-лист для проверки конфигурации fpm процесса.

Переходим на UNIX-сокеты

Наверное первое, на что следует обратить внимание, это то как проходят данные от веб-сервера к вашим php процессам. Это отражено в директиве listen:

listen = 127.0.0.1:9000

В случае если установлен адрес:порт, то данные идут через стек TCP, и это наверное не очень хорошо. Если же там путь к сокету, например:

listen = /var/run/php5-fpm.sock

то данные идут через unix-сокет.

Почему все таки стоит перейти на unix-сокет? UDS (unix domain socket), в отличии от TCP, имеют значительные преимущества:

  • не требуют переключение контекста, UDS используют netisr;
  • датаграмма UDS записывается напрямую в сокет назначения;
  • отправка дейтаграммы UDS требует меньше операций (нет контрольных сумм, нет TCP-заголвоков, не производится маршрутизация);

И вот некоторые тесты:

TCP средняя задержка: 6 us
UDS средняя задержка: 2 us
PIPE средняя задержка: 2 us

TCP средняя пропускная способность: 253702 msg/s
UDS средняя пропускная способность: 1733874 msg/s
PIPE средняя пропускная способность: 1682796 msg/s

Таким образом, у UDS задержка на ~66% меньше и пропускная способность в 7 раз больше TCP. Поэтому, скорей всего стоит перейти на UDS.

Также следует убедиться, что веб-сервер (или любой другой процесс, которому необходима коммуникация) имеет доступ на чтение/запись в ваш сокет. Для этого существуют настройки listen.group и listen.mode. Проще всего - запускать оба процесса от одного пользователя или группы, в нашем случае php-fpm и веб-сервер будет запущен с группой www-data:

listen.owner = www-data
listen.group = www-data
listen.mode = 0660

Проверяем выбранный механизм обработки событий

Для работы с эффективной работы с I/O (вводом-выводом, дескрипторами файлов/устройств/сокетов) стоит проверить правильно ли указана настройка events.mechanism. Его значение зависит от ОС, для чего есть подсказка в документации.

Выбор типа пула - dynamic / static / ondemand

Также, стоит обратить внимание на настройки менеджер процессов (pm). По сути это главный процесс (master process), который будет управлять всеми дочерними (которые выполняют код приложения) по определенной логике, которая собственно и описана в файле конфигурации.

Всего доступно 3 схемы управления процессами:

  • dynamic
  • static
  • ondemand

Наиболее простой - это static. Схема его работы заключается в следующем: запустить фиксированное количество дочерних процессов, и поддерживать их в рабочем состоянии. Данная схема работы не очень эффективна, так как количество запросов и их нагрузка может меняться время от времени, а количество дочерних процессов нет - они всегда занимают определенный объем ОЗУ.

dynamic пул позволит решить эту проблему, он регулирует количество дочерних процессов исходя из значений конфигурационного файла, изменяя их в большую или меньшую сторону, в зависимости от нагрузки. Данный пул больше всего подходит для сервера приложений, в котором необходима быстрая реакция на запрос, работа с пиковой нагрузкой, требуется экономия ресурсов (за счет уменьшения дочерних процессов при простое).

ondemand пул очень похож на static, но он не запускает дочерних процессов при старте главного процесса. Только когда придет первый запрос - будет создан первый дочерний процесс, и по истечении определенного времени ожидания (указанного в конфигурации) он будет уничтожен. Потому он актуален для серверов с ограниченными ресурсами, или той логики которая не требует быстрой реакции.

Утечки памяти и OOM killer

OOM Killer представляет собой компонент ядра Linux, защитный механизм, призванный решать проблемы с нехваткой физической памяти (OOM — Out of memory). При обнаружении недостатка памяти OOM Killer «убивает» наименее важный по его мнению процесс, посылая ему сигнал KILL (исключения составляют лишь init и ядерные нити (kernel threads)). Сообщение об этом появляется в журнале /var/log/syslog в виде:

Out of memory: Kill process **** (****) score **** or sacrifice child
Killed process **** (****)

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

pm.max_requests
request_terminate_timeout

pm.max_requests это максимальное количество запросов, которое обработает дочерний процесс, прежде чем будет уничтожен. Принудительное уничтожение процесса позволяет избежать ситуации в которой память дочернего процесса “разбухнет” по причине утечек (т.к процесс продолжает работу после от запроса к запросу). С другой стороны, слишком маленькое значение приведет к частым перезапускам, что приведет к потерям в производительности. Стоит начать с значения в 1000, и далее уменьшить или увеличить это значение.

request_terminate_timeout устанавливает максимальное время выполнения дочернего процесса, прежде чем он будет уничтожен. Это позволяет избегать долгих запросов, если по какой-либо причине было изменено значение max_execution_time в настройках интерпретатора. Значение стоит установить исходя из логики обрабатываемых приложений, скажем 60s (1 минута).

Настройка dynamic пула

Для основного сервера приложения, ввиду явных преимуществ, часто выбирают dynamic пул. Его работа описана следующими настройками:

  • pm.max_children - максимальное количество дочерних процессов
  • pm.start_servers - количество процессов при старте
  • pm.min_spare_servers - минимальное количество процессов, ожидающих соединения (запросов для обработки)
  • pm.max_spare_servers - максимальное количество процессов, ожидающих соединения (запросов для обработки)

Для того, чтобы корректно установить эти значения, необходимо учитывать:

  • сколько памяти в среднем потребляет дочерний процесс
  • объем доступного ОЗУ

Выяснить среднее значение памяти на один php-fpm процесс на уже работающем приложении можно с помощью планировщика:

# ps -ylC php-fpm --sort:rss
S   UID   PID  PPID  C PRI  NI   RSS    SZ WCHAN  TTY          TIME CMD
S     0  1445     1  0  80   0  9552 42588 ep_pol ?        00:00:00 php5-fpm

Нам необходимо среднее значение в колонке RSS (размер резидентной памяти в килобайтах). В моем случае это ~20Мб. В случае, если нагрузки на приложения нет, можно использовать Siege, для создания простейшей нагрузки на php-fpm.

Объем общей / доступной / используемой памяти можно посмотреть с помощью free:

# free -m
            total   used    free   ...
Memory:     4096    600     3496     

Далее, возьмем за основу формулу для расчета pm.max_children, и проведем расчет на примере:

Total Max Processes = (Total Ram - (Used Ram + Buffer)) / (Memory per php process)

Всего ОЗУ: 4Гб
Используется ОЗУ: 1000Мб
Буфер безопасности: 400Мб
Память на один дочерний php-fpm процесс (в среднем): 30Мб

Максимально возможное кол-во процессов = (4096 - (1000 + 400)) / 30 = 89
Четное количество: 89 округлили в меньшую сторону до 80

Значение остальных директив можно установить исходя из ожидаемой нагрузки на приложение, а также учесть чем еще занимается сервер кроме работы php-fpm (скажем СУБД также требует ресурсов). В случае наличия множества задач на сервере - стоит снизить количество начальных / максимальных процессов.

К примеру учтем, что на сервере находится 2 пула www1 и www2 (2 веб-ресурса), тогда конфигурация каждого из них может выглядеть как:

pm.max_children = 40
pm.start_servers = 15
pm.min_spare_servers = 15
pm.max_spare_servers = 25