Нечетные колебания производительности с php-fpm и nginx

Я запускаю нагрузочный тест на веб-сервис. Это php-приложение, работающее на php-fpm и nginx с fastcgi. Бэкэнд MySQL используется только для небольших операций чтения.

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

Вот образец производительности, который я вижу (визуализируется с nmon):

введите описание изображения здесь

Выпадение всегда совпадает с короткой паузой, которую имеет мой инструмент нагрузочного тестирования - locust.io - когда он заканчивает наращивать до пикового уровня, который я установил для теста.

Моя гипотеза: в этот краткий момент php-fpm мастер думает, что груз исчез и начинает убивать рабочих; он не может реагировать достаточно быстро, когда движение возвращается полным ходом через мгновение.

Чего я не совсем понимаю, так это того, почему он так и не смог вернуться к нему: я вижу это колебание на неопределенный срок для всех 4 серверов приложений за балансировщиком нагрузки.

Вот мой конфиг пула php-fpm:

[www]
user = www-data
group = www-data
listen = /var/run/php5-fpm.sock
listen.group = www-data
listen.mode = 0660
pm = dynamic
pm.max_children = 100
pm.start_servers = 40
pm.min_spare_servers = 40
pm.max_spare_servers = 100
pm.max_requests = 10000

Я уже подтвердил, что это не проблема с базой данных - я увидел точно такое же поведение после удвоения числа MySQL-ведомых.

Чем это вызвано? Как я могу это остановить?

РЕДАКТИРОВАТЬ:

Вот график, который демонстрирует то, что я вижу. Обратите внимание, что частота отказов, как правило, возрастает так же, как пик user_count, и постепенно снижается.

user_count против fail_ratio

2 ответа

Как насчет управления памятью? В последние недели я провел несколько тестов по симлару и довел один сервер до предела. Я видел много изменений в памяти. В моем случае огромное количество данных было занесено в своп вместо оперативной памяти для обработки нагрузки. После одного теста у меня был действительно странный результат, ОЗУ больше не использовалось, и все было утеряно. Возможно, это замедляет следующие запросы.

Это пример изображения, как выглядел мой своп после нагрузочного теста

Что происходит с дисковым вводом-выводом и блокировкой? Предположительно, если ваш процесс связан с процессором до точки, где это изменяется, тогда что-то еще занято, и это, скорее всего, ваш диск.

Достигаете ли вы ограничений памяти, из-за которых вы начинаете менять местами? Сколько оперативной памяти используют ваши процессы PHP (RSS)? Сколько оперативной памяти у вас есть в наличии? Получаете ли вы аналогично колеблющуюся производительность, если отбрасываете число процессов PHP? На каком уровне появляется колебание?

Обратите внимание, что pm.max_children = 100 вероятно, слишком высоко. Если вы не имеете дело с долгосрочными запросами, такими как большие загрузки, вам, вероятно, лучше уменьшить его. Я не решаюсь указывать число, не зная, что делает система, но, вероятно, что-то в диапазоне 5-40 будет работать намного лучше. pm.max_requests также, вероятно, будет слишком высоким. Вы, вероятно, обнаружите, что вы получаете небольшую выгоду и, скорее всего, значительное ухудшение, если оно превышает 100 или около того, и если то, что запускается php, сильно изменчиво и потребляет память, или у вас есть утечки памяти, то вы будете лучше уменьшая это немного дальше. Если вы действительно не знаете, что работает, начните с каждой из этих настроек около 30 и экспериментируйте.

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

На что работа strace с отчетом о процессах PHP занимает много времени? Вы можете посмотреть на это с помощью составной команды по следующим направлениям:

(ps wwaux | grep '^www-data.*php' |  awk '{print $2}' \
  | xargs -n 1 -P 32 strace -r -p ) 2>&1 
  | perl -ne '($n) = /^ *(\d*\.\d*)/; print "$n\t$_" if ((defined $n) and ($n > 0.01))'
Другие вопросы по тегам