it-swarm.com.ru

PHP5-FPM случайным образом начинает потреблять много процессора

Я столкнулся с действительно странной проблемой, которую я не уверен, как отлаживать дальше. У меня есть экземпляр Amazon Ubuntu NGINX + PHP5-FPM + APC, и на нем установлен веб-сайт, представляющий собой сложную PHP среду. Пытаясь отладить проблему, я сократил поток до следующего: включается много больших классов, создаются основные объекты, запускается сессия, массив конфигов извлекается из memcached, XML-файл извлекается из memcached, HTML шаблоны включены, вывод отправляется клиенту.

Затем я использую инструмент http_load для загрузки сайта под нагрузкой 20 запросов в секунду: http_load -timeout 10 -rate 20 -fetches 10000 ./urls.txt

Что происходит дальше, довольно странно. top показывает набор процессов php5-fpm, каждый из которых занимает несколько% процессорного времени, и все работает гладко, например так:

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
28440 www-data 20 0 67352 10m 5372 S 4.3 1.8 0:20.33 php5-fpm
28431 www-data 20 0 67608 10m 5304 S 3.3 1.8 0:16.77 php5-fpm
28444 www-data 20 0 67352 10m 5372 S 3.3 1.8 0:17.17 php5-fpm
28445 www-data 20 0 67352 10m 5372 S 3.0 1.8 0:16.83 php5-fpm
28422 www-data 20 0 67608 10m 5292 S 2.3 1.8 0:18.99 php5-fpm
28424 www-data 20 0 67352 10m 5368 S 2.0 1.8 0:16.59 php5-fpm
28438 www-data 20 0 67608 10m 5304 S 2.0 1.8 0:17.91 php5-fpm
28439 www-data 20 0 67608 10m 5304 S 2.0 1.8 0:23.34 php5-fpm
28423 www-data 20 0 67608 10m 5292 S 1.7 1.8 0:20.02 php5-fpm
28430 www-data 20 0 67608 10m 5300 S 1.7 1.8 0:15.77 php5-fpm
28433 www-data 20 0 67352 10m 5372 S 1.7 1.8 0:17.08 php5-fpm
28434 www-data 20 0 67608 10m 5292 S 1.7 1.8 0:18.56 php5-fpm
20648 memcache 20 0 51568 8192 708 S 1.3 1.3 2:51.06 memcached
28420 www-data 20 0 69876 13m 6300 S 1.3 2.3 0:20.89 php5-fpm
28421 www-data 20 0 67608 10m 5300 S 1.3 1.8 0:21.19 php5-fpm
28429 www-data 20 0 9524 2260 992 S 1.3 0.4 0:11.68 nginx
28435 www-data 20 0 67608 10m 5304 S 1.3 1.8 0:18.58 php5-fpm
28437 www-data 20 0 67352 10m 5372 S 1.3 1.8 0:17.87 php5-fpm
28441 www-data 20 0 67608 10m 5292 S 1.3 1.8 0:20.75 php5-fpm

Затем через некоторое время, которое может составлять от одной секунды до нескольких минут, несколько (обычно два) процесса php5-fpm внезапно потребляют весь процессор:

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
28436 www-data 20 0 67608 10m 5304 R 48.5 1.8 0:23.68 php5-fpm
28548 www-data 20 0 67608 10m 5276 R 45.2 1.7 0:07.62 php5-fpm
28434 www-data 20 0 67608 10m 5292 R 2.0 1.8 0:23.28 php5-fpm
28439 www-data 20 0 67608 10m 5304 R 2.0 1.8 0:26.63 php5-fpm

В этот момент все застревает и все новые запросы HTTP истекают. Если я остановлю http_load tool, php5-fpm будет зависать там много минут. Интересно, что если я сделаю php5-fpm stop, процессы php5-fpm исчезнут, но любые команды, использующие файловую систему, будут иметь проблемы при выполнении. Например. если я попытаюсь загрузить файл через ssh, top покажет следующее, что займет много минут, чтобы начать фактическую загрузку:

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3298 sshd 20 0 7032 876 416 R 75.2 0.1 0:04.52 sshd
3297 sshd 20 0 7032 876 416 R 24.9 0.1 0:04.49 sshd

Журнал ошибок PHP обычно имеет это:

[05-Dec-2012 20:31:39] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 8 children, there are 0 idle, and 58 total children
[05-Dec-2012 20:32:08] WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 16 children, there are 0 idle, and 66 total children

Журнал ошибок Nginx заполняется этими записями:

2012/12/05 20:31:36 [error] 4800#0: *5559 connect() to unix:/dev/shm/php-fpm-www.sock failed (11: Resource temporarily unavailable) while connecting to upstream, client: ..., server: ec2-....compute-1.amazonaws.com, request: "GET /usa/index.php?page=contact_us HTTP/1.0", upstream: "fastcgi://unix:/dev/shm/php-fpm-www.sock:", Host: "ec2-....compute-1.amazonaws.com"

В медленном журнале PHP-FPM ничего интересного нет, перестановка никогда не происходит, и мне не удалось собрать другие интересные факты о проблеме. Я прошел много итераций изменений файла конфигурации, самые последние из которых были

nginx.conf: http://Pastebin.com/uaD56hJF

pool.d/www.conf: http://Pastebin.com/mFeeUULC

=== ОБНОВЛЕНИЕ 1 ===

конфигурация сайта: http://Pastebin.com/qvinVNhB

=== ОБНОВЛЕНИЕ 2 ===

Также обнаружил, что dmesg сообщает об ошибках, подобных этой

[6483131.164331] php5-fpm[28687]: segfault at b6ec8ff4 ip b78c3c32 sp bff551f0 error 4 in ld-2.13.so[b78b5000+1c000]

=== ОБНОВЛЕНИЕ 3 ===

На всякий случай у нас есть новый микроэкземпляр Amazon EC2, чтобы исключить возможные проблемы с оборудованием. Также я использую php-fastcgi сейчас, чтобы исключить возможные ошибки fpm. Другие отличия незначительны, я думаю, что единственное изменение - это Ubuntu-> Debian. Та же проблема все еще происходит, за исключением того, что теперь серверу удается немного восстановиться после max_execution_time секунд (и затем снова всплывает). 

Я пытался играть с отдельным test.php, и я не уверен, что это та же проблема, но, по крайней мере, в top он выглядит одинаково. Я создал test.php и включил несколько библиотек, которые принадлежат нашей среде. Библиотеки ничего не делают, кроме определения классов или включения других библиотек, которые определяют классы. Я проверил с APC, и все это успешно обслуживается им. Я начал давить test.php со скоростью 200 запросов в секунду, и через некоторое время произошло то же самое. За исключением того, что теперь мне удалось получить некоторые ошибки, говорящие «слишком много открытых файлов». Хотя это происходит не всегда, иногда он просто начинает отсчет времени без вывода ошибки, и несколько процессов php зависают, потребляя весь процессор. Я немного поиграл с этим, но я думаю, что здесь есть корреляция - контролируя количество включенных библиотек или немного меняющихся запросов/секунду, я могу контролировать, когда произойдет всплеск процессора. Я увеличил соответствующие переменные ОС, но проблема все еще существует, хотя для этого требуется больше времени (также обратите внимание, что я установил ограничения на значения в N раз больше, чем общее количество запросов, которые я делаю во время тестов).

fs.file-max = 70000
...
*       soft    nofile   10000
*       hard    nofile  30000
...
worker_rlimit_nofile 10000;
...
(reloaded all the configs and made sure the new system vars actually took affect)

Итак, следующее лучшее и единственное объяснение, которое я могу придумать, заключается в том, что, хотя APC должен извлекать файлы из памяти, внутренне он реализован таким образом, что все еще использует дескриптор файла, когда PHP include-s являются называется. И либо потому, что он освобождает их с задержкой, либо когда в какой-то неудачный момент в одно и то же время приходит слишком много запросов, система запускает наши дескрипторы, а вновь поступающие HTTP-запросы быстро помещаются в огромную очередь. Я попробую это как-то проверить.

12
Eugene

Я управлял веб-сайтом с подобной конфигурацией в течение многих месяцев, без времени простоя Я посмотрел ваш конфиг, и он выглядит нормально. Тем не менее, я сделал свой конфиг довольно давно.

Я хотел бы рассмотреть возможность сокращения pm.max_requests = 10000 до чего-то более разумного, например pm.max_requests = 500. Это просто означает, что «не используйте каждый экземпляр для более чем X запросов». Хорошо, если это число не слишком велико, потому что это дает вам устойчивость к возможным ошибкам PHP движка.

Я думаю, что настоящая проблема, скорее всего, в ваших PHP скриптах. Трудно сказать, не зная больше.

Правка: Подумайте о том, чтобы раскомментировать ;request_terminate_timeout = 0 и установить для него что-то вроде request_terminate_timeout = 20. Ваши сценарии должны будут завершиться в течение 20 секунд. Скорее всего, вы увидите изменение в поведении, но я думаю, что ваш сайт может остаться в живых. Это указывает на ошибку сценария PHP.

EDIT2: мой собственный конфиг php-fpm выглядит следующим образом:

[example.com]
listen = /var/run/sockets/example.com.socket
user = www-data
group = www-data
pm = dynamic
pm.start_servers = 5
pm.max_children = 15
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 500
php_flag[expose_php] = off
php_flag[short_open_tag] = on

EDIT3: я заметил что-то неожиданное в вашей конфигурации nginx, но это может быть ничего.

Вы используете fastcgi_ignore_client_abort on;, который вызывает проблемы в рабочих процессах в старых версиях nginx. Я не видел эту проблему сам, так как я запускаю пользовательскую компиляцию последней версии. Вот описание проблемы на сайте nginx:

В 1.0.2 POST запросы не обрабатываются правильно, когда fastcgi_ignore_client_abort установлен на, что может привести к работникам процессы segfaulting. Переключение fastcgi_ignore_client_abort обратно на по умолчанию (выкл) должен решить эту проблему.

9
Kevin A. Naudé

Простой трюк, но очень полезный, чтобы уменьшить загрузку процессора до 50%, просто отредактируйте конфигурацию php-fpm:

pm = dynamic

и измените его на:

pm = ondemand
3
Animanga

Я сейчас прохожу эту проблему и хотел указать вам на этот пост:

Как определить, какой скрипт выполняется в процессе PHP-FPM

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

Забавно, это было на сервере, который был безупречно быстрым. Я думаю, что обновление WordPress (плагин или ядро) может быть очень ответственным.

1
Berto

У меня такая же проблема. Я попытался перенастроить PHP-FPM и NGINX и не очень далеко. Один из наших парней отключил v8js.php ( http://php.net/manual/en/book.v8js.php ), и это решило проблему. Я предлагаю отключить любые модули php, пока вы не найдете нарушителя спокойствия. Надеюсь, это кому-нибудь поможет.

0
Allen

Поведение PHP-FPM на моем Сервере такое же, как и у вас. узкое место где-то наверняка.
Возникает вопрос: как найти узкое место в Nginx - PHP-FPM - Mysql? Самый быстрый способ выяснить это: включить Slowlog для PHP-FPM.
Добавьте строки ниже в ваш пул php-fpm.conf и убедитесь, что путь существует

request_slowlog_timeout = 10
slowlog = /var/log/php-fpm/slow.$pool.log

Прочитав обратную трассировку журнала, вы сможете узнать, почему PHP-FPM потратил так много ресурсов ЦП или времени ожидания. Вот мои случаи:

[28-Dec-2018 14:56:55]  [pool laravel] pid 19061
script_filename = /public_html/index.php
[0x00007efdda4d8100] hasChildren() /public_html/laravel/vendor/symfony/Finder/Iterator/ExcludeDirectoryFilterIterator.php:75
[0x00007ffe31cd9e40] hasChildren() unknown:0
[0x00007ffe31cda200] next() unknown:0
[0x00007ffe31cda540] next() unknown:0
[0x00007ffe31cda880] next() unknown:0
[0x00007efdda4d7fa8] gc() /public_html/laravel/vendor/laravel/framework/src/Illuminate/Session/FileSessionHandler.php:91
[0x00007efdda4d7e50] gc() /public_html/laravel/vendor/laravel/framework/src/Illuminate/Session/Middleware.php:159
[0x00007efdda4d7d48] collectGarbage() /public_html/laravel/vendor/laravel/framework/src/Illuminate/Session/Middleware.php:128
[0x00007efdda4d7c20] closeSession() /public_html/laravel/vendor/laravel/framework/src/Illuminate/Session/Middleware.php:79
[0x00007efdda4d7ac8] handle() /public_html/laravel/vendor/laravel/framework/src/Illuminate/Cookie/Queue.php:47
[0x00007efdda4d7930] handle() /public_html/laravel/vendor/laravel/framework/src/Illuminate/Cookie/Guard.php:51
[0x00007efdda4d7818] handle() /public_html/laravel/vendor/stack/builder/src/Stack/StackedHttpKernel.php:23
[0x00007efdda4d76e0] handle() /public_html/laravel/vendor/laravel/framework/src/Illuminate/Foundation/Application.php:641
[0x00007efdda4d7598] run() 
/public_html/index.php:51

Обратный след упоминает об этих ключевых словах: 

"cookie" "session" "collectGarbage()" "laravel"

Я продолжаю поиск и TADA, Laravel, используя метод RANDOM, чтобы очистить истекший сеанс. И в моей конфигурации, PHP использую SSD для обработки сессии.
Когда число сессий становится «очень большим», PHP тратит больше времени на обработку => высокая загрузка ЦП. 

У нас может быть много видов узких мест, мы можем просто знать это, когда мы «отлаживаем» это.

Приятного расследования.

0
minhhq