为什么 php-fpm 在没有服务器负载的情况下每秒会产生和销毁数百个子进程?

为什么 php-fpm 在没有服务器负载的情况下每秒会产生和销毁数百个子进程?

显示php7.0-fpm.log每秒生成数百个子进程,然后立即被销毁。这种情况不停地发生。日志如下所示:

[09-Mar-2017 02:58:25] NOTICE: [pool www] child 4980 started
[09-Mar-2017 02:58:25] NOTICE: [pool www] child 4978 exited with code 0 after 0.014658 seconds from start
[09-Mar-2017 02:58:25] NOTICE: [pool www] child 4981 started
[09-Mar-2017 02:58:25] NOTICE: [pool www] child 4980 exited with code 0 after 0.014354 seconds from start
[09-Mar-2017 02:58:25] NOTICE: [pool www] child 4982 started
[09-Mar-2017 02:58:25] NOTICE: [pool www] child 4979 exited with code 0 after 0.015170 seconds from start
[09-Mar-2017 02:58:25] NOTICE: [pool www] child 4983 started
[09-Mar-2017 02:58:25] NOTICE: [pool www] child 4981 exited with code 0 after 0.014709 seconds from start
[09-Mar-2017 02:58:25] NOTICE: [pool www] child 4984 started
[09-Mar-2017 02:58:25] NOTICE: [pool www] child 4982 exited with code 0 after 0.014741 seconds from start
[09-Mar-2017 02:58:25] NOTICE: [pool www] child 4985 started
[09-Mar-2017 02:58:25] NOTICE: [pool www] child 4983 exited with code 0 after 0.014727 seconds from start
[09-Mar-2017 02:58:25] NOTICE: [pool www] child 4986 started

设置来自/etc/php/7.0/fpm/php-fpm.conf

pid = /run/php/php7.0-fpm.pid
error_log = /var/log/php7.0-fpm.log
include=/etc/php/7.0/fpm/pool.d/*.conf

设置来自/etc/php/7.0/fpm/pool.d/www.conf

pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
;pm.process_idle_timeout = 10s;
;pm.max_requests = 500
catch_workers_output = yes
php_flag[display_errors] = on
php_admin_value[error_log] = /var/log/phperrors.log
php_admin_flag[log_errors] = on

其余行均用 (默认设置)注释掉;。这是 Ubuntu 16.04,使用默认软件包。PHP 和 Nginx 版本如下:

php-fpm7.0 -v
PHP 7.0.13-0ubuntu0.16.04.1 (fpm-fcgi)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies
    with Zend OPcache v7.0.13-0ubuntu0.16.04.1, Copyright (c) 1999-2016, by Zend Technologies

nginx -v
nginx version: nginx/1.10.0 (Ubuntu)

未进行任何调整(除了启用日志记录)。此服务器尚未部署到生产环境,因此没有用户负载。

为什么 php-fpm 每秒会生成并立即销毁数百个子进程?这是配置错误,还是 Ubuntu 16.04 附带了有缺陷的 php-fpm 版本?

答案1

既不是配置错误,也不是版本有缺陷。事实上,没有什么可担心的。

进程退出和重生速度如此之快的原因是您pm.max_requests在 php-fpm 池配置文件中使用了默认值,因为它通过分号;符号进行了注释。要了解pm.max_requests参数的含义,您可以阅读以下取自默认配置的描述:

pm.max_requests= int

每个子进程在重生之前应执行的请求数。这对于解决第三方库中的内存泄漏问题很有用。对于无休止的请求处理,请指定“0”。相当于 PHP_FCGI_MAX_REQUESTS。默认值:0。

而您的是 0,因为它被注释掉了。您可以将其设置为 100-500 左右(根据您的需要),以便您的 php-fpm 在处理完该数量的请求后回收该进程。

顺便说一句,您应该注意到日志文件中的这些消息仅供参考,没有任何错误,所以不用担心。 可以通过将中的参数的值warning改为 来避免这些日志条目。 它几乎显示了所有内容 - 比 level 少一点- 因为默认值设置为。noticelog_levelphp-fpm.confdebugnotice

从默认配置中获取:

日志级别= 字符串

错误日志级别。可能的值:alert、error、warning、notice、debug。默认值:notice。

祝你好运

答案2

这发生在我的一台装有 Ubuntu 14(PHP 5)和 16(PHP 7)的服务器上。使用早期版本时,会有一些延迟,但使用最新版本时,只要 FPM 进程处理一个有问题的请求,它就会变得很疯狂。

我注意到有问题的请求确实发生exec在类似以下情况中https://stackoverflow.com/questions/44400072/php-fpm-forever-respawning-children-when-executing-uglifycss但我还是不明白这应该如何导致。这似乎与在后台执行某些操作(与&操作员一起)密切相关。

我无法提供实际的解决方案,仅提供从 cron 运行的不太好的解决方法脚本:

#!/bin/sh -e

v=${1:-7.0}
poolname=${2:-www}

# requires Restart=always and KillMode=process in /lib/systemd/system/php7.0-fpm.service!
retire_fpm() {
  logger -p user.crit -t $0 "$(sudo pkill -e php$v-fpm || sudo pkill -e php-fpm$v || echo "aiee, could not find php fpm version $v to retire" >&2)"
}

if sudo initctl version 2>/dev/null; then # upstart
  logdir=/var/log
  logfile=$logdir/upstart/php$v-fpm.log
else
  logdir=/var/log
  logfile=$logdir/php$v-fpm.log
fi

logfile_huge=$(test -e $logfile && find $logfile -size +200M || true)
if [ -n "$logfile_huge" ]; then
  logger -p user.crit -t $0 "demolishing $logfile to prevent the partition from filling up"
  cp /dev/null $logfile
fi

rotated_logfile_huge=$(test -e $logfile.1 && find $logfile.1 -size +200M || true)
if [ -n "$rotated_logfile_huge" ]; then
  logger -p user.crit -t $0 "demolishing $logfile.1 to prevent the partition from filling up"
  cp /dev/null $logfile.1
fi

if [ ! -e $logfile ]; then
  if ! df -P $logdir/ | awk '/^\// && $5+0 > 50 { exit(1) }'; then
    logger -p user.crit -t $0 "initiating php$v-fpm termination (init will restart it) because there is no $logfile yet the partition is filling up"
  else
    logger -p user.crit -t $0 "initiating php$v-fpm termination (init will restart it) because there is no $logfile, something went awry"
  fi
  retire_fpm
  exit
fi

logfile_grew=$(find $logfile -size +5M || true)

if [ -z "$logfile_grew" ]; then
  exit 0
fi

# 5 lines: handle recovery: one started line, one exited line, three post-signal lines
recent_fast_respawns=$(tail -5 $logfile | egrep -c ' NOTICE: .pool '$poolname'. child .+ exited with code 0 after 0....... seconds from start')

if [ "$recent_fast_respawns" -le 1 ]; then
  logger -p user.notice -t $0 "php$v-fpm log $logfile indicates a lot of recent activity, but only $recent_fast_respawns recent fast respawns, leaving it be"
  exit 0
fi

logger -p user.crit -t $0 "initiating php$v-fpm termination (init will restart it) because $logfile indicates $recent_fast_respawns recent fast respawns"
retire_fpm

这根本就不应该存在......但我一直在更新它。<叹气>

相关内容