PHP7.3-FPM с Apache: Неизвестный тайм-аут выполнения запроса скрипта
Я настроил Apache 2.4 MPM Event с PHP7.3-FPM на довольно загруженном веб-сервере следующим образом:
Timeout 90
<Proxy "unix:/run/php/php7.3-fpm.sock|fcgi://php-fpm">
ProxySet disablereuse=on timeout=90
</Proxy>
<FilesMatch ".+\.php$">
SetHandler proxy:fcgi://php-fpm
</FilesMatch>
Конфигурация PHP в /etc/php/7.3/fpm/php.ini установлена на
max_execution_time=60
PHP-FPM настраивается в /etc/php/7.3/fpm/pool.d/www.conf для
request_terminate_timeout=90
Время ожидания чтения настраивается в /etc/apache2/mods-enabled/reqtimeout.conf следующим образом:
RequestReadTimeout header=20-120,minrate=50
RequestReadTimeout body=60-120,minrate=50
В журнале FPM теперь я вижу каждую минуту 1-2 рабочих для неизвестных запросов, которые убиваются через 90+ секунд.
[16-May-2019 09:25:32] WARNING: [pool www] child 105567, script '' (request: " ") execution timed out (113.002653 sec), terminating
[16-May-2019 09:25:32] WARNING: [pool www] child 105567 exited on signal 15 (SIGTERM) after 4050.136381 seconds from start
[16-May-2019 09:25:32] NOTICE: [pool www] child 110414 started
Если я не установлю request_terminate_timeout
чтобы убить этих рабочих, они остаются дольше (~5 минут) в состоянии "Чтение заголовков" и блокируют пул PHP-FPM.
Кажется, потоки в Apache MPM не блокируются. Ничто не мешает максимальным рабочим ценностям.
Как я могу увидеть, к какому сценарию / запросу принадлежат эти работники PHP? Почему эти сценарии работают даже после max_execution_time
60 секунд истек? Как можно избежать блокировки пула PHP такими запросами?
Я подозреваю, что иногда могут быть неполные HTTPS-запросы, которые как-то запускают работника PHP. Есть ли способ избежать запуска PHP работника для них?
1 ответ
Как упоминает @constantin-galbenu в своем комментарии , Apache<Proxy>
Директива не очень хорошо сочетается с моделью многопроцессорной обработки prefork PHP-FPM, как описано в https://bugs.php.net/bug.php?id=69890 .
[2019-05-02 10:03 UTC] депутат на webfactory dot de
Для справки, в руководстве Apache по адресу https://httpd.apache.org/docs/current/mod/mod_proxy_fcgi.html#examples говорится:
Включить повторное использование соединений с серверной частью FCGI, например PHP-FPM.
Имейте в виду, что PHP-FPM (на момент написания статьи, февраль 2018 г.) использует модель prefork, а именно, каждый из его рабочих процессов может обрабатывать одно соединение одновременно. По умолчанию mod_proxy (настроенный с параметром Enablereuse=on) разрешает пул соединений ThreadsPerChild с серверной частью для каждого процесса httpd при использовании многопоточного MPM (например, работника или события), поэтому следует принять во внимание следующие варианты использования:
При загрузке HTTP/1.1 это, скорее всего, приведет к созданию подключений MaxRequestWorkers к серверной части FCGI.
При загрузке HTTP/2 из-за реализации mod_http2 возникают дополнительные рабочие потоки h2, которые могут принудительно создавать другие серверные соединения. Общее количество подключений в пулах может превысить значение MaxRequestWorkers.
Максимальное количество рабочих процессов PHP-FPM должно быть настроено с умом, поскольку существует вероятность того, что все они будут «заняты» обработкой простаивающих постоянных соединений без возможности создания новых, и опыт конечного пользователя ухудшится. быть кучей таймаутов HTTP-запросов.
Моя интерпретация заключается в том, что при включении Enablereuse=on каждый рабочий процесс/поток Apache MPM может иметь открытое соединение с PHP-FPM. На странице состояния PHP-FPM они будут отображаться как «Чтение заголовков...» (или подобное). Эти процессы кажутся активными (ожидающими) PHP-FPM и поэтому не завершаются.
Моя собственная проблема заключалась в том, что веб-серверы использовали модуль многопроцессорной обработки событий Apache (MPM), передающий выполнение PHP в PHP-FPM, используя пример конфигурации из документации Apache mod_proxy_fcgi :
<FilesMatch "\.php$">
# Note: The only part that varies is /path/to/app.sock
SetHandler "proxy:unix:/path/to/app.sock|fcgi://localhost/"
</FilesMatch>
# Define a matching worker.
# The part that is matched to the SetHandler is the part that
# follows the pipe. If you need to distinguish, "localhost; can
# be anything unique.
<Proxy "fcgi://localhost/" enablereuse=on max=10>
</Proxy>
В этой конфигурации я видел необъяснимые ошибки прокси-сервера 503 от Apache, при этом приложение периодически не отвечало, пока PHP-FPM не был перезапущен. После добавленияrequest_terminate_timeout = 5m
моему/etc/php-fpm.d/www.conf
Чтобы принудительно уничтожить длительные запросы PHP-FPM, мое приложение стало немного более стабильным, и я начал видеть ошибки, подобные следующим, в моих и менее частых сбоях, которые длились несколько минут, прежде чем восстанавливались без вмешательства:
[04-Jan-2023 15:19:26] WARNING: [pool www] child 349975, script '' (request: " ") execution timed out (362.004673 sec), terminating
[04-Jan-2023 15:19:26] WARNING: [pool www] child 349975 exited on signal 15 (SIGTERM) after 1200.012433 seconds from start
После удаленияenablereuse=on
флаг из моей конфигурации Apache, я больше не вижу вышеуказанных ошибок тайм-аута в моем/var/log/php-fpm/error.log
. Новая конфигурация:
<FilesMatch "\.php$">
<If "-f %{REQUEST_FILENAME}">
# Pick one of the following approaches
#
# Use the standard TCP socket
#SetHandler "proxy:fcgi://localhost:9000"
# If your version of httpd is 2.4.9 or newer (or has the back-ported feature), you can use the unix domain socket
#SetHandler "proxy:unix:/path/to/app.sock|fcgi://localhost/"
SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost/"
</If>
</FilesMatch>
# Defining a worker will improve performance
# And in this case, re-use the worker (dependent on support from the fcgi application)
# If you have enough idle workers, this would only improve the performance marginally
#
# enablereuse=on is only available in Apache >= 2.4.11
<Proxy "fcgi://localhost/" max=10>
</Proxy>