max_children

Ubuntu PHP max_children 常用指令

PHP FPM Max Children

在 php fpm 的 error log 发现执行绪不太够用,需要设定开启新执行绪

[24-Oct-2018 07:43:58] WARNING: [pool www] server reached pm.max_children setting (5), consider raising it
[24-Oct-2018 08:27:52] WARNING: [pool www] server reached pm.max_children setting (5), consider raising it
[24-Oct-2018 10:57:17] WARNING: [pool www] server reached pm.max_children setting (5), consider raising it
[24-Oct-2018 11:37:32] WARNING: [pool www] server reached pm.max_children setting (5), consider raising it

设定档路径

/etc/php/7.1/fpm/pool.d/www.conf

在设定档中可以看到类似以下的设定方式

pm.max_children = 10
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 8

Process Manager 行程调配规则参数说明

参数 说明
pm PHP-FPM Process Manager 行程调配规则
pm.start_servers PHP-FPM 服务在一开始启动时,要配置多少个行程
pm.min_spare_servers PHP-FPM 最小闲置行程的数量
pm.max_spare_servers PHP-FPM 最大闲置行程的数量
pm.max_requests 单一 PHP-FPM 最多可以处理多少个连线,当一个工作行程处理的连线数达到这个值的时候,就会强制关闭此行程,重新产生另一个新的行程
pm = dynamic
参数 说明
static 固定行程数量(数量为 pm.max_children) ,效能很好,但很佔记忆体
dynamic 动态行程数量(根据 pm.max_children、pm.start_servers、pm.min_spare_servers、pm.max_spare_servers 动态调整),根据使用量用多少开多少,但当使用量比较低时,会保留一些行程,随时等着接收新的连线
ondemand 动态行程数量(根据 pm.max_children、pm.start_servers、pm.min_spare_servers、pm.max_spare_servers 动态调整),用多少开多少

pm.max_children 最大执行程序数量

最大执行程序数量是针对自己的主机规格不同去做设定的,当你主机有较大的记忆体,则可以设定更多的执行程序

Total Max Processes = (Total Ram - (Used Ram + Buffer)) / (Memory per php process)

最大执行程序 = (总记忆体 - (已使用记忆体 + Buffer)) / (每个 php 执行绪需要记忆体)

pm.max_children 数量:可用记忆体(MB) / 大约 50MB

确认每个 php 执行绪需要记忆体

因为每个 php 执行的记忆体及效率会针对不同的程式环境不同,而有不同的消耗记忆体,可以使用下列指令去取得 php-fpm 执行绪消耗的记忆体数量

ps -ylC php-fpm 执行绪完整名称 –sort:rss

范例

其中的 php-fpm 执行绪完整名称 要看看你系统是用哪个版本的 php,而会有不同版本名称的 php-fpm,像是:

ps -ylC php-fpm --sort:rss
ps -ylC php-fpm7.0 --sort:rss
ps -ylC php-fpm7.1 --sort:rss

在列出来 php-fpm 使用的资源后,可以看到 RSS 栏位为使用的记忆体大小,31692 表示为 31692 kb,大概就是 31M

$ ps -ylC php-fpm7.1 --sort:rss
S   UID   PID  PPID  C PRI  NI   RSS    SZ WCHAN  TTY          TIME CMD
S    33 22275 16692  1  80   0 31692 212882 -     ?        08:00:00 php-fpm7.0
S    33 22092 16692  1  80   0 40708 231684 -     ?        08:00:02 php-fpm7.0
S    33 22023 16692  1  80   0 41136 231888 -     ?        08:00:05 php-fpm7.0
S    33 22038 16692  1  80   0 41204 231744 -     ?        08:00:04 php-fpm7.0

但每个 php-fpm 程序的记忆体不尽相同,我们可以用下列指令去计算平均使用的记忆体大小是多少

ps –no-headers -o “rss,cmd” -C php-fpm 执行绪完整名称 | awk ‘{ sum+=$1 } END { printf ("%d%s\n", sum/NR/1024,“Mb”) }’

也是一样针对你系统是用哪个版本的 php,而会有不同版本名称的 php-fpm,像是:

ps --no-headers -o "rss,cmd" -C php-fpm  | awk '{ sum+=$1 } END { printf ("%d%s\n", sum/NR/1024,"Mb") }'
ps --no-headers -o "rss,cmd" -C php-fpm7.0  | awk '{ sum+=$1 } END { printf ("%d%s\n", sum/NR/1024,"Mb") }'
ps --no-headers -o "rss,cmd" -C php-fpm7.1  | awk '{ sum+=$1 } END { printf ("%d%s\n", sum/NR/1024,"Mb") }'

抓出来的平均使用记忆体大概为 44 MB,但为了抓 Buffer,我们大概抓 50 MB 左右

$ ps --no-headers -o "rss,cmd" -C php-fpm7.0  | awk '{ sum+=$1 } END { printf ("%d%s\n", sum/NR/1024,"Mb") }'
44Mb

确认可用的记忆体数量

php-fpm 可以用的记忆体为:剩馀还可用的记忆体 + (php-fpm 平均使用记忆体 * 目前 php-fpm 开启数量)

使用 free -m 取得目前的记忆体使用状况,总记忆体是 3272 M,已经使用了 1539M,剩馀还可用的记忆体有 1021 M

$ free -m
              total        used        free      shared  buff/cache   available
Mem:           3762        1539        1021          84        2417        2686
Swap:             0           0           0

而从下列指令中,取得 php-fpm 平均使用记忆体为 44M

ps –no-headers -o “rss,cmd” -C php-fpm 执行绪完整名称 | awk ‘{ sum+=$1 } END { printf ("%d%s\n", sum/NR/1024,“Mb”) }’

从下列指令中列出目前所有 php-fpm 执行绪数量为 41 个(直接去计算清单出现几行 php-fpm 资源状况即可知道总共开了几个 php-fpm 执行绪)

ps -ylC php-fpm 执行绪完整名称 –sort:rss

所以 php-fpm 可以用的记忆体为 1021 M + 44 M * 41 个 = 2743M

最大执行程序数量 = php-fpm 可以用的记忆体 / 每个 php 执行绪需要记忆体(Buffer 数值)

2743M / 50M = 54.86

为了不要让所有记忆题全部消耗完,而没有空间去执行其他非 php 的程序,所以我们这边会抓 pm.max_children 大概最多使用个 50 个 执行绪

pm.max_children = 50

start_server 官方建议算法是 min_spare_servers + (max_spare_servers - min_spare_servers) / 2

min_spare_servers 跟 max_spare_servers 就取个大概就好,不要让他一直开开关关即可

pm.start_servers = 20
pm.min_spare_servers = 13
pm.max_spare_servers = 26

防止 php-fpm 执行绪处理过多 request 导致 Memory leak

pm.max_requests = 500
request_terminate_timeout = 30s

让每个子执行绪同时处理超过 500 个 request 就自动移除此执行绪,避免 Memory Leak 执行绪卡在那边动弹不得

而执行时间超过 30 秒的请求则自动中断掉,建议设定为与 php.inimax_execution_time 相同

最后设定值会像是:

pm = dynamic
pm.max_children = 50
pm.start_servers = 20
pm.min_spare_servers = 13
pm.max_spare_servers = 26
pm.max_requests = 500
request_terminate_timeout = 30s

记录观察

为了持续观察 php-fpm 执行序地处理状况,我们可以把请求执行时间过慢的 Request 记录下来,在之后后续可以持续做除错改进,这裡设定纪录执行超过 10 秒的执行绪状况

; slowlog = /var/log/php7.0-fpm-$pool.log.slow
slowlog = /var/log/php7.1-fpm-$pool.log.slow
request_slowlog_timeout = 10s

设定完成后可以进行测试,确认改过的设定档案没有问题

php-fpm7.0 -t
php-fpm7.1 -t
$ php-fpm7.1 -t
[03-Jul-2019 15:53:15] NOTICE: configuration file /etc/php/7.1/fpm/php-fpm.conf test is successful

确认后记得重启 php-fpm 服务即可生效

sudo service php7.0-fpm restart
sudo service php7.1-fpm restart

参考资料