php env php fpm
PHP Profi
Квест → Как хакнуть форму
Всё, что вы должны знать о переменных окружения в PHP Перевод
Переменные окружения, используемые в конфигурации, являются на сегодняшний день основным методом установки в приложении таких настроек, как учетные данные базы, API ключи, секретные ключи и всего, что является различным в зависимости от того, где развертывается приложение. Сейчас такие настройки попадают в код через окружение, вместо прямого прописывания в файлах конфигурации или, того хуже, хардкода прямо в коде.
Давайте подробнее взглянем на то:
Мы не будем рассматривать как настроить переменные окружения в вашем веб-сервере / Docker-е / crontab-ах. т. к. это зависит от системы, программного обеспечения, а мы хотим сосредоточиться на самих переменных окружения.
Если ваш хостинг использует Docker Swarm или AWS, все будет немного по-другому, например, т. к. они решили подсовывать файлы на файловую систему вашего контейнера, чтобы внедрить ваши секретные ключи, а не использовать переменные окружения. Это очень специфично для этих платформ и не является распространённым вариантом для всех.
Env vars 101
При запуске программы, она наследует все переменные окружения от своих родителей. Так что если вы установите переменную YOLO в значение covfefe в bash, а затем выполните команду, вы сможете прочитать YOLO в любом дочернем процессе.
Поскольку эта переменная определена только локально, мы не можем прочитать её из другого терминала (другого родителя). Идея в том, чтобы убедиться, что ваше приложение всегда наследует нужные переменные.
Вы можете установить переменную окружения с помощью export = :
Лучшие практики на сегодня
Возможно, вы уже знаете о двенадцати факторной методологии для создания надежных и масштабируемых приложений (если нет, то я предлагаю вам сделать перерыв и проверить его). Глава о конфигурации объясняет, почему сохранение конфигов в окружении это правильный путь:
Манифест также довольно хорошо описывает что должно быть в коде и что должно быть в окружении – не кладите все настройки приложения в него, только то, что отличается у одного развернутого стенда от другого.
Я читал(а) в Интернете, что переменные окружения опасны
Некоторые статьи расскажут вам, что переменные окружения вредны для ваших секретных ключей. Главная причина заключается в том, что любой процесс наследует от своего родителя переменные, все из них. Так что если у вас очень секретная настройка в окружающей среде, дочерние процессы будут иметь доступ к нему:
Дочерние процессы могут рассматривать переменную окружения, как что-то публичное, что можно записать в логи, включить в отчеты об ошибках, вывести пользователю в случае ошибки. Они могут допустить утечку ваших секретных ключей.
Альтернатива – старые текстовые файлы, со строгими Unix-правами. Но что действительно должно быть сделано, очистка окружения при запуске дочернего процесса, которому вы не доверяете, как это делает nginx. По умолчанию nginx удаляет все переменные окружения, унаследованные от своего родительского процесса, за исключением переменной TZ. Проблема решена!
Всегда запускайте процессы, которым вы не доверяете, в ограниченной среде.
Даже если вы доверяете вашему коду, вы всё равно должны быть очень осторожны и передавать ваши переменные как можно меньшему количеству процессов – кто и как их будет использовать вы никогда не знаете (внутри драма в NPM-проекте).
Подготовка приложения
Библиотеки «Dot Env» в помощь
vlucas/phpdotenv, самая популярная библиотека на данный момент:
Есть несколько хороших плюшек, таких как возможность помечать некоторые переменные, как обязательные. (используется фреймворком Laravel)
josegonzalez/dotenv, ориентирована на безопасность:
Эта библиотека не заполнит суперглобальные переменные по умолчанию:
Она поддерживает обязательные переменные, фильтрацию, и может выбрасывать исключения, когда переменная перезаписывается.
symfony/dotenv, новый малыш на этом поприще:
На packagist есть ещё куча других и я даже боюсь спрашивать, почему каждый пишет тот же парсер снова и снова.
Но все они используют ту же логику:
Эта рекомендация хорошо работает, когда каждый локально имеет ту же инфраструктуру: тот же пароль к БД, тот же сервер и порт. Т. к. мы используем Docker Compose на всех наших проектах, у нас никогда нет никаких различий в настройках одного разработчика от настроек другого. Если у вас нет такой плюшки, просто позвольте разработчикам перезаписывать настройки по умолчанию, импортировав два файла:
Затем на продакшене, вы не должны загружать эти значения по умолчанию:
Если вы так не сделаете, и ваш хостинг-провайдер забудет передать переменную, то запустите код в продакшене с настройками от дева, а это не приведёт ни к чему хорошему.
Подводные камни, на которые вы должны обратить внимание ⚠
Конфликты имен
Нейминг – это сложно, и переменные окружения не являются исключением из этого правила.
Поэтому при именовании переменных окружения, вы должны быть осторожными и допускать как можно меньше конфликтов имен. Ситуация усложняется тем, что нет официального списка зарезервированных имен. Хорошая практика – использовать префиксы пользовательских переменных.
Отсутствие переменных во время выполнения
У вас есть два варианта в случае, если переменная отсутствует: либо бросить исключение, или использовать значение по умолчанию. Решать вам, но второй вариант молчаливый. Что может принести вред во многих случаях.
Как только вы захотите использовать переменные окружения, вы должны установить их везде:
Про последний легко забыть, но так как сценарии могут разогревать кеш приложения (как Symfony-вские). да, отсутствие переменной может привести к поломке деплоя. Будьте осторожны с этим и добавите проверку при запуске приложения.
Префикс HTTP_
Вы помните httpoxy уязвимость? Она возникала при поиске http-клиентом переменной в окружении таким образом, что её можно было установить через простой http-заголовок.
Некоторые DotEnv-библиотеки также предотвращают переопределение таких переменных, например, Symfony-компонент.
Потокобезопасность функции getenv()
У меня плохие новости: в некоторых конфигурациях, использование функции getenv() приведет к неожиданным результатам. Эта функция не потокобезопасна!
Переменные окружения – всегда строки
Одной из главных проблем является то, что сейчас в PHP есть указание типов, а наши настройки не всегда правильно набраны.
В Symfony теперь можно преобразовывать variables, а даже больше – чтение файла, декодирование json. …
Переменные окружения везде или нет
На данный момент существует много споров между использованием переменных окружения, файлов, или их смеси: переменная окружения ссылается на файл конфигурации. Дело в том, что несмотря на то, что это считается лучшей практикой, переменные окружения не представляют больших преимуществ.
Переменные окружения и PHP
Поговорим про конфигурацию и переменные окружения.
Полезные ссылки по теме:
Допустим, у нас есть PHP приложение. Приложению нужна какая-то конфигурация, как минимум настройки подключения к базе данных, возможно настройки подключения к Redis, к почтовому серверу.
Фреймворки общего назначения дают нам достаточно большую гибкость по настройке работы самого фреймворка. Если заглянуть в папку config в Laravel, то увидим там множество различных php файлов описывающих параметры подключения к базе, кеширование, логирование, аутентификацию и многое другое. При этом не все параметры на самом деле являются секретами или зависят от окружения. Есть такие параметры, которые мы задаём на старте разработки проекта и они справедливы для всех окружений и не представляют секрета, например, пути к папкам для шаблонов ( config/view.php в Laravel) или имена файлов для логов.
Получается, часть конфигурации является секретной или зависит от окружения и её мы не хотим добавлять в git репозиторий (максимум, мы можем добавить некий example файл в git репозиторий). А часть конфигурации – это по сути зафиксированные для данного проекта значения и их, конечно, нужно сохранять в git.
Чтобы отделить одни от других, можно развести их по разным конфигурационным файлам.
Для секретной или платформозависимой части конфигурации можно использовать так называемые переменные окружения, которые уже давно были изобретены в unix системах. А в наше время к ним подталкивает и методология 12-факторных приложений, и такие инструменты как Docker, Kubernetes и различные сорта Serverless.
Однако в PHP с переменными окружения есть некоторая путаница давайте разберёмся.
Итак, у нас есть переменные окружения, которые предоставляет нам операционная система (и Linux, и Windows, и macOS). Есть средства чтобы их прочитать из PHP приложения. Казалось бы найдено идеальное место для хранения секретов и настроек зависящих от окружения! Но как эти переменные окружения задать? Тут целая наука.
Впрочем, не будем пока сдаваться и отказываться от переменных окружения, продолжим рассуждать так будто мы их используем.
Ещё один нюанс: php-fpm по умолчанию не передаёт переменные окружения, заданные операционной системой, в свои процессы-воркеры. За это отвечает настройка clear_env в файле конфигурации пула php-fpm (обычно у нас один пул, который называется www и его конфигурация соответственно в файле www.conf ). С этим сталкиваешься, когда пытаешься пробросить переменные окружения в php-fpm внутри Docker контейнера.
Слишком много мороки с настройкой этих переменных окружения!
.env файлы по задумке не рекомендуется использовать в production. Это удобное текстовое описание для конфигурации в процессе разработки, но в production лучше всё-таки пользоваться переменными окружения, предоставляемыми операционной системой.
Подводя итог, сформулируем несколько тезисов:
Конфигурирование и переменные окружения — казалось бы, тема простая, но есть своя глубина и разные подходы. Копайте глубже, это интересно!
Php env php fpm
FPM использует синтаксис php.ini для своего файла конфигурации php-fpm.conf и файлов конфигурации пулов.
Список глобальных директив php-fpm.conf
Путь к PID-файлу. По умолчанию: none.
Уровень журналирования ошибок. Возможные значения: alert, error, warning, notice, debug. По умолчанию: notice.
Ограничить журналирование для журналируемых линиях, что позволяет записывать сообщения длиной более 1024 символов без упаковки (wrapping). Значение по умолчанию: 1024. Доступно с PHP 7.3.0.
Экспериментальное журналирование без дополнительной буферизации. Значение по умолчанию: yes. Доступно с PHP 7.3.0.
Используется для указания, какой тип программ будет логировать сообщения. По умолчанию: daemon.
Предшествует любому сообщению. Если у вас запущено несколько экземпляры FPM, вы можете изменить значение по умолчанию на то, которое вам необходимо. По умолчанию: php-fpm.
При данном числе рабочих процессов, завершённых с SIGSEGV или SIGBUS за промежуток времени, установленный emergency_restart_interval FPM будет перезагружен. Значение 0 означает ‘Off’ (отключено). По умолчанию: 0 (Off).
Время, в течение которого дочерние процессы ждут ответа на сигналы мастер-процессу. Доступные единицы измерения: s(секунды), m(минуты), h(часы) или d(дни). Единица измерения по умолчанию: секунды. Значение по умолчанию: 0.
Максимальное количество процессов, которое может породить FPM. Это сделано для того, чтобы контролировать глобальное количество процессов, когда используется большой пул динамического PM. Используйте с осторожностью. По умолчанию: 0.
Запустить FPM в фоновом режиме. Установите значение ‘no’, чтобы запустить FPM в диспетчере для отладки. По умолчанию: yes.
Устанавливает rlimit открытых файловых дескрипторов для мастер-процесса. По умолчанию: Устанавливает rlimit для открытого дескриптора файла мастер-процесса(?).
Устанавливает rlimit максимального размера ядра для мастер-процесса. По умолчанию 0.
Указывает, какой событийный механизм будет использован FPM. Возможны такие варианты: select, pool, epoll, kqueue (*BSD), port (Solaris). По умолчанию: не установлено (автоопределение).
Если FPM собран с интеграцией с systemd, указывает интервал, в секундах, между оповещениями systemd о своём состоянии. Для отключения задайте 0. По умолчанию: 10.
Список директив для пулов.
С помощью FPM вы можете запускать несколько пулов процессов с различными настройками. Эти параметры могут быть переданы пулу.
Адрес, который будет принимать FastCGI-запросы. Синтаксис: ‘ip.add.re.ss:port’, ‘port’, ‘/path/to/unix/socket’. Эта опция обязательна для каждого пула.
Список IPv4-адресов FastCGI-клиентов, которые имеют право подключения. Эквивалент переменной окружения среды FCGI_WEB_SERVER_ADDRS в оригинальном PHP FastCGI (5.2.2+). Имеет смысл только с TCP-сокетом. Каждый адрес должен быть отделен запятой. Если оставить значение пустым, то соединения будут приниматься с любого IP. По умолчанию: any. Можно использовать IPv6.
Задаёт права для unix-сокета, если они используются. В Linux для разрешения соединений к веб-серверу, должны быть установлены права на чтение/запись. Во многих основанных на BSD-системах возможность соединения не зависит от прав доступа. Значение по умолчанию: используется пользователь и группа, от имени которого запущен сервер, установлен режим 0660.
Если поддерживается список управления доступом (ACL) POSIX, вы можете настроить его с помощью этой опции. Если задано, то listen.owner и listen.group будут проигнорированы. Значение задаётся списком имён, разделённых запятой.
Unix-пользователь FPM-процессов. Этот параметр является обязательным.
Unix-группа FPM-процессов. Если не установлен, группа по умолчанию равняется имени пользователя.
Этот параметр устанавливает ограничение на число одновременных запросов, которые будут обслуживаться. Эквивалент директивы ApacheMaxClients с mpm_prefork и переменной окружения среды PHP_FCGI_CHILDREN в в оригинальном PHP FastCGI.
Ссылка, по которой можно посмотреть страницу состояния FPM. Если значение не установлено, то страница статуса отображаться не будет. Значение по умолчанию: none.
Ссылка на ping-страницу мониторинга FPM. Если значение не установлено, ping-страница отображаться не будет. Может быть использовано для тестирования извне, чтобы убедиться, что FPM жив и отвечает. Обратите внимание, что значение должно начинаться с косой черты (/).
Эта директива может быть использована на настройки ответа на ping-запрос. Ответ формируется как text/plain со кодом ответа 200. Значение по умолчанию: pong.
Установить флаг процесса dumpable (PR_SET_DUMPABLE prctl), даже если the пользователь процесса или группа отличается от пользователя мастер-процесса. Это позволяет создавать дамп ядра процесса и выполнить ptrace процесса для пользователя пула. Значение по умолчанию: no. Доступно с PHP 7.0.29, 7.1.17 и 7.2.5.
Задаёт префикс для вычисления пути
Таймаут для обслуживания одного запроса, после чего рабочий процесс будет завершён. Этот вариант следует использовать, когда опция ‘max_execution_time’ в php.ini не останавливает выполнение скрипта по каким-то причинам. Значение ‘0’ означает ‘выключено’. Доступные единицы измерения: s(econds), m(inutes), h(ours) или d(ays). Значение по умолчанию: 0.
Таймаут для обслуживания одного запроса, после чего PHP backtrace будет сохранён в файл ‘slowlog’. Значение ‘0’ означает ‘выключено’. Доступные единицы измерения: s(econds), m(inutes), h(ours) или d(ays). Значение по умолчанию: 0.
Устанавливает лимит дескрипторов открытых файлов rlimit для дочерних процессов в этом пуле. Значение по умолчанию: определяется значением системы.
Устанавливает максимальное количество используемых ядер rlimit для дочерних процессов в этом пуле. Возможные значения: ‘unlimited’ или целое число большее или равное 0. Значение по умолчанию: определяется значением системы.
Директория chroot окружения при старте. Это значение должно быть определено как абсолютный путь. Если значение не установлено, chroot не используется.
Chdir изменяет текущую директорию при старте. Это значение должно быть определено как абсолютный путь. Значение по умолчанию: текущая директория или / при использовании chroot.
Перенаправление STDOUT и STDERR рабочего процесса в главный лог ошибок. Если не установлен, STDOUT и STDERR будут перенаправлены в /dev/null в соответствии со спецификацией FastCGI. Значение по умолчанию: no.
Включите оформление выхода (output decoration) для вывода worker-процесса когда опция catch_workers_output включена. Значение по умолчанию: yes. Доступно с PHP 7.3.0.
Очищает окружение в worker-процессах FPM. Предотвращает попадание произвольных переменных окружения в worker-процессы FPM, очищая окружение у worker-процессах до того, как переменные окружения, указанные в этой конфигурации пула будут добавлены. По умолчанию: Yes.
Лог-файл доступа. Значение по умолчанию: не установлено
Можно передать дополнительные переменные окружения и обновить настройки PHP для определённого пула. Для этого вам необходимо добавить следующие параметры в файл настройки пула.
Пример #1 Передача переменных окружения и настроек PHP пулу
Начиная с версии 5.3.3 настройки PHP можно устанавливать через веб-сервер.
Пример #2 Установка настроек PHP в nginx.conf
Так как эти настройки передаются в php-fpm как FastCGI-заголовки, php-fpm не должен быть привязан к общедоступному адресу из мира. В противном случае любой сможет изменить настройки PHP. Смотрите также listen.allowed_clients.
User Contributed Notes 12 notes
It seems there is no way to get informed about the access log format codes that are used or can be used. All I found is the source code.
It would really help, not to have open questions when deploying php-fpm. I constantly struggle with file paths for example, but that is another topic.
case ‘%’: /* ‘%’ */
case ‘C’: /* %CPU */
case ‘d’: /* duration µs */
case ‘e’: /* fastcgi env */
case ‘f’: /* script */
case ‘l’: /* content length */
case ‘m’: /* method */
case ‘M’: /* memory */
case ‘n’: /* pool name */
case ‘o’: /* header output */
case ‘p’: /* PID */
case ‘P’: /* PID */
case ‘q’: /* query_string */
case ‘Q’: /* ‘?’ */
case ‘r’: /* request URI */
case ‘R’: /* remote IP address */
case ‘s’: /* status */
case ‘T’:
case ‘t’: /* time */
case ‘u’: /* remote user */
the doc is lacking a lot of things it seems.
With Apache, mod_proxy_fcgi and php-fpm, if you want to have a generic pool and several vhost with different php configuration, you can use the ProxyFCGISetEnvIf directive and the PHP_ADMIN_VALUE environment variable. It does not work with PHP_ADMIN_FLAG even for boolean directives.
PHP directives must be separated by spaces and a \n.
ProxyFCGISetEnvIf «true» PHP_ADMIN_VALUE «open_basedir=/var/www/toto/:/tmp/ \n session.save_path=/var/www/toto/session \n display_errors=On \n error_reporting=-1»
The default value for listen.backlog isn’t exactly «unlimited».
Check for a sysctl value like kern.somaxconn (OpenBSD) or net.core.somaxconn (Linux).
Crank it up if you need more PHP workers than the default value. Then adjust listen.backlog in your php-fpm configuration file to the same value.
Be very carrefull when using ProxyFCGISetEnvIf within a Apache virtual host configuration using a shared PHP-FPM pool. Values defined like this are shared across all the Apache virtual hosts within a pool worker, may resulting in strange behaviours depending on the requests chronology.
Correction for my previous note.
I wrote «The ‘index’ directive that is used in php-fpm.conf».
But obviously I meant «The ‘include’ directive».
This means that, if you have multiple pools with similar configurations, you can create a file ‘default-values.inc’ like so:
pm = dynamic
pm.max_children = X
pm.min_spare_servers = X
pm.max_spare_servers = X
access.log = /var/log/php-fpm/$pool.access
access.format = «%R %u [%t] \»%m %r\» %s %d %l»
slowlog = /var/log/php-fpm/$pool.slow
And then include that file in each pool configuration like so:
——
[vhost1.example.com]
user = www-vhost1
group = www-vhost1
This makes things a bit more transparent, and it could potentially save some time if you decide to change settings.
Сравниваем PHP FPM, PHP PPM, Nginx Unit, React PHP и RoadRunner
Тестирование производилось с помощью Yandex Tank.
В качестве приложения использовались Symfony 4 и PHP 7.2.
Целью являлось сравнение характеристик сервисов при разных нагрузках и нахождение оптимального варианта.
Для удобства все собрано в docker-контейнеры и поднимается с помощью docker-compose.
Под катом много таблиц и графиков.
Исходный код лежит тут.
Все примеры команд, описанные в статье, должны выполняться из директории проекта.
Приложение
Приложение работает на Symfony 4 и PHP 7.2.
Отвечает только на один роут и возвращает:
В каждом контейнере настроен PHP:
Логи пишутся в stderr:
/config/packages/prod/monolog.yaml
Кеш пишется в /dev/shm:
/src/Kernel.php
В каждом docker-compose запускаются три основных контейнера:
Обработка запросов ограничивается двумя инстансами приложения (по числу ядер процессора).
Сервисы
PHP FPM
Менеджер PHP процессов. Написан на C.
Команда для запуска приложения с docker-compose:
PHP PPM
Менеджер PHP процессов. Написан на PHP.
Команда для запуска приложения с docker-compose:
Nginx Unit
Сервер приложений от команды Nginx. Написан на С.
Чтобы передать переменные окружения из файла конфигурации nginx-unit, необходимо поправить php.ini:
Команда для запуска приложения с docker-compose:
React PHP
Библиотека для событийного программирования. Написана на PHP.
Если использовать для воркера флаг —reboot-kernel-after-request, то Symfony Kernel будет инициализироваться заново на каждый запрос. При таком подходе не нужно следить за памятью.
Команда для запуска приложения с docker-compose:
Road Runner
Web-сервер и менеджер PHP-процессов. Написан на Golang.
Если использовать для воркера флаг —reboot-kernel-after-request, то Symfony Kernel будет инициализироваться заново на каждый запрос. При таком подходе не нужно следить за памятью.
Команда для запуска приложения с docker-compose:
Тестирование
Тестирование производилось с помощью Yandex Tank.
Приложение и Yandex Tank были на разных виртуальных серверах.
Характеристики виртуального сервера с приложением:
Virtualization: KVM
CPU: 2 cores
RAM: 4096 МБ
SSD: 50 GB
Connection: 100MBit
OS: CentOS 7 (64x)
Для тестов 1000/10000 rps добавлен сервис php-fpm-80
Для него использовалась конфигурация php-fpm:
Yandex Tank заранее определяет, сколько раз ему нужно выстрелить в цель, и не останавливается, пока не кончатся патроны. В зависимости от скорости ответа сервиса время теста может быть больше, чем задано в конфигурации тестов. Из-за этого графики разных сервисов могут иметь разную длину. Чем медленнее отвечает сервис, тем длиннее будет его график.
Для каждого сервиса и конфигурации Yandex Tank проводился всего один тест. Из-за этого цифры могут быть неточными. Важно было оценить характеристики сервисов относительно друг друга.
100 rps
Конфигурация phantom Yandex Tank
Ссылки с детальным отчетом
Перцентили времени ответа
95%(ms) | 90%(ms) | 80%(ms) | 50%(ms) | HTTP OK(%) | HTTP OK(count) | |
---|---|---|---|---|---|---|
php-fpm | 9.9 | 6.3 | 4.35 | 3.59 | 100 | 57030 |
php-ppm | 9.4 | 6 | 3.88 | 3.16 | 100 | 57030 |
nginx-unit | 11 | 6.6 | 4.43 | 3.69 | 100 | 57030 |
road-runner | 8.1 | 5.1 | 3.53 | 2.92 | 100 | 57030 |
road-runner-reboot | 12 | 8.6 | 5.3 | 3.85 | 100 | 57030 |
react-php | 8.5 | 4.91 | 3.29 | 2.74 | 100 | 57030 |
react-php-reboot | 13 | 8.5 | 5.5 | 3.95 | 100 | 57030 |
Мониторинг
cpu median(%) | cpu max(%) | memory median(MB) | memory max(MB) | |
---|---|---|---|---|
php-fpm | 9.15 | 12.58 | 880.32 | 907.97 |
php-ppm | 7.08 | 13.68 | 901.72 | 913.80 |
nginx-unit | 9.56 | 12.54 | 923.02 | 943.90 |
road-runner | 5.57 | 8.61 | 992.71 | 1,001.46 |
road-runner-reboot | 9.18 | 12.67 | 848.43 | 870.26 |
react-php | 4.53 | 6.58 | 1,004.68 | 1,009.91 |
react-php-reboot | 9.61 | 12.67 | 885.92 | 892.52 |
Графики
График 1.1 Среднее время ответа в секунду
График 1.2 Средняя нагрузка процессора в секунду
График 1.3 Среднее потребление памяти в секунду
500 rps
Конфигурация phantom Yandex Tank
Ссылки с детальным отчетом
Перцентили времени ответа
95%(ms) | 90%(ms) | 80%(ms) | 50%(ms) | HTTP OK(%) | HTTP OK(count) | |
---|---|---|---|---|---|---|
php-fpm | 13 | 8.4 | 5.3 | 3.69 | 100 | 285030 |
php-ppm | 15 | 9 | 4.72 | 3.24 | 100 | 285030 |
nginx-unit | 12 | 8 | 5.5 | 3.93 | 100 | 285030 |
road-runner | 9.6 | 6 | 3.71 | 2.83 | 100 | 285030 |
road-runner-reboot | 14 | 11 | 7.1 | 4.45 | 100 | 285030 |
react-php | 9.3 | 5.8 | 3.57 | 2.68 | 100 | 285030 |
react-php-reboot | 15 | 12 | 7.2 | 4.21 | 100 | 285030 |
Мониторинг
cpu median(%) | cpu max(%) | memory median(MB) | memory max(MB) | |
---|---|---|---|---|
php-fpm | 41.68 | 48.33 | 1,006.06 | 1,015.09 |
php-ppm | 33.90 | 48.90 | 1,046.32 | 1,055.00 |
nginx-unit | 42.13 | 47.92 | 1,006.67 | 1,015.73 |
road-runner | 24.08 | 28.06 | 1,035.86 | 1,044.58 |
road-runner-reboot | 46.23 | 52.04 | 939.63 | 948.08 |
react-php | 19.57 | 23.42 | 1,049.83 | 1,060.26 |
react-php-reboot | 41.30 | 47.89 | 957.01 | 958.56 |
Графики
График 2.1 Среднее время ответа в секунду
График 2.2 Средняя нагрузка процессора в секунду
График 2.3 Среднее потребление памяти в секунду
1000 rps
Конфигурация phantom Yandex Tank
Ссылки с детальным отчетом
Перцентили времени ответа
95%(ms) | 90%(ms) | 80%(ms) | 50%(ms) | HTTP OK(%) | HTTP OK(count) | |
---|---|---|---|---|---|---|
php-fpm | 11050 | 11050 | 9040 | 195 | 80.67 | 72627 |
php-fpm-80 | 3150 | 1375 | 1165 | 152 | 99.85 | 89895 |
php-ppm | 2785 | 2740 | 2685 | 2545 | 100 | 90030 |
nginx-unit | 98 | 80 | 60 | 21 | 100 | 90030 |
road-runner | 27 | 15 | 7.1 | 3.21 | 100 | 90030 |
road-runner-reboot | 1110 | 1100 | 1085 | 1060 | 100 | 90030 |
react-php | 23 | 13 | 5.6 | 2.86 | 100 | 90030 |
react-php-reboot | 28 | 24 | 19 | 11 | 100 | 90030 |
Мониторинг
cpu median(%) | cpu max(%) | memory median(MB) | memory max(MB) | |
---|---|---|---|---|
php-fpm | 12.66 | 78.25 | 990.16 | 1,006.56 |
php-fpm-80 | 83.78 | 91.28 | 746.01 | 937.24 |
php-ppm | 66.16 | 91.20 | 1,088.74 | 1,102.92 |
nginx-unit | 78.11 | 88.77 | 1,010.15 | 1,062.01 |
road-runner | 42.93 | 54.23 | 1,010.89 | 1,068.48 |
road-runner-reboot | 77.64 | 85.66 | 976.44 | 1,044.05 |
react-php | 36.39 | 46.31 | 1,018.03 | 1,088.23 |
react-php-reboot | 72.11 | 81.81 | 911.28 | 961.62 |
Графики
График 3.1 Среднее время ответа в секунду
График 3.2 Среднее время ответа в секунду (без php-fpm, php-ppm, road-runner-reboot)
График 3.3 Средняя нагрузка процессора в секунду
График 3.4 Среднее потребление памяти в секунду
10000 rps
Конфигурация phantom Yandex Tank
Ссылки с детальным отчетом
Перцентили времени ответа
95%(ms) | 90%(ms) | 80%(ms) | 50%(ms) | HTTP OK(%) | HTTP OK(count) | |
---|---|---|---|---|---|---|
php-fpm | 11050 | 11050 | 11050 | 1880 | 70.466 | 317107 |
php-fpm-80 | 3260 | 3140 | 1360 | 1145 | 99.619 | 448301 |
php-ppm | 2755 | 2730 | 2695 | 2605 | 100 | 450015 |
nginx-unit | 1020 | 1010 | 1000 | 980 | 100 | 450015 |
road-runner | 640 | 630 | 615 | 580 | 100 | 450015 |
road-runner-reboot | 1130 | 1120 | 1110 | 1085 | 100 | 450015 |
react-php | 1890 | 1090 | 1045 | 58 | 99.996 | 449996 |
react-php-reboot | 3480 | 3070 | 1255 | 91 | 99.72 | 448753 |
Мониторинг
cpu median(%) | cpu max(%) | memory median(MB) | memory max(MB) | |
---|---|---|---|---|
php-fpm | 5.57 | 79.35 | 984.47 | 998.78 |
php-fpm-80 | 85.05 | 92.19 | 936.64 | 943.93 |
php-ppm | 66.86 | 82.41 | 1,089.31 | 1,097.41 |
nginx-unit | 86.14 | 93.94 | 1,067.71 | 1,069.52 |
road-runner | 73.41 | 82.72 | 1,129.48 | 1,134.00 |
road-runner-reboot | 80.32 | 86.29 | 982.69 | 984.80 |
react-php | 73.76 | 82.18 | 1,101.71 | 1,105.06 |
react-php-reboot | 85.77 | 91.92 | 975.85 | 978.42 |
График 4.1 Среднее время ответа в секунду
График 4.2 Среднее время ответа в секунду (без php-fpm, php-ppm)
График 4.3 Средняя нагрузка процессора в секунду
График 4.4 Среднее потребление памяти в секунду
Итоги
Здесь собраны графики, отображающие изменение характеристик сервисов в зависимости от нагрузки. При просмотре графиков стоит учитывать, что не все сервисы ответили на 100% запросов.
График 5.1 95% перцентиль времени ответа
График 5.2 95% перцентиль времени ответа (без php-fpm)
График 5.3 Максимальная нагрузка процессора
График 5.4 Максимальное потребление памяти
Оптимальным решением (без изменения кода), на мой взгляд, является менеджер процессов Nginx Unit. Он показывает хорошие результаты в скорости ответа и имеет поддержку компании.
В любом случае подход к разработке и инструменты нужно выбирать индивидуально в зависимости от ваших нагрузок, ресурсов сервера и возможностей разработчиков.
UPD
Для тестов 1000/10000 rps добавлен сервис php-fpm-80
Для него использовалась конфигурация php-fpm: