PHP5-FPM随机开始消耗大量CPU

17

我遇到了一个非常奇怪的问题,不确定如何进一步进行调试。我在一个NGINX + PHP5-FPM + APC的Amazon Ubuntu实例上安装了一个复杂的PHP框架网站。在尝试调试问题时,我将流程简化为以下几点:包含大量大类、创建主对象、启动会话、从memcached检索配置数组、从memcached检索XML文件、包含HTML模板、将输出发送到客户端。

然后我使用http_load工具让该网站承受每秒20个请求的负载:http_load -timeout 10 -rate 20 -fetches 10000 ./urls.txt

接下来发生的事情非常奇怪。top显示出一堆php5-fpm进程被生成,每个进程占用少量CPU资源,并且一切运行顺利,就像这样:

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进程突然占用了所有的CPU资源:

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工具,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检查过,所有这些都能成功地被服务。然后我开始以每秒200个请求的速度对test.php进行压力测试,经过一段时间后,发生了同样的事情。除了现在我设法得到了一些错误,说"打开的文件太多"。它并不总是发生,有时候仅仅开始超时而没有输出错误,几个PHP进程会卡住消耗全部CPU。我只是简单地玩了一下,但我认为这里有一个相关性 - 通过控制包含库的数量或略微变化的请求/秒率,我可以控制CPU飙升的发生时间。我增加了相关的操作系统变量,但问题仍然存在,尽管需要更长的时间才会发生(还要注意,我已将限制设置为测试期间所做请求的总数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时仍然使用文件描述符。由于它们可能会延迟释放或在某个不幸的时刻有太多请求同时到达,系统会耗尽描述符,并且新到达的HTTP请求会快速堆积成一个巨大的队列。我会尝试进行测试。

你能发布一下站点本身的nginx配置吗?(不是你的主要配置) - Kevin A. Naudé
当然,这是它的链接:http://pastebin.com/qvinVNhB - Eugene
有同样的问题。我的情况是PHP72-FPM在一个非索引表上执行了大量的数据库查询。在我的情况下,代码编写有误。如果问题与mysql相关,则应该使用以下选项来了解如何搜索解决方案:log_queries_not_using_indexes = ON。 - snex
5个回答

13

我已经运行了一个类似配置的网站很多个月,从未出现过宕机。我查看了你的配置,看起来没问题。话虽如此,我的配置是相当久以前做的。

我建议将 pm.max_requests = 10000 这一项减少到更为合理的数字,比如说 pm.max_requests = 500。这只是意味着“不要让每个实例处理超过X个请求”。最好不要将这个数字设置得太高,因为这样会在可能出现PHP引擎错误时增强你的韧性。

我认为真正的问题很可能在于你的PHP脚本,但由于缺乏更多信息,很难确定。

编辑: 可以考虑取消注释 ;request_terminate_timeout = 0 并将其设置为类似于 request_terminate_timeout = 20 的数字。这样,你的脚本将必须在20秒内完成。你很可能会看到行为变化,但我认为你的网站可能会保持在线。那就说明可能是PHP脚本出现了错误。

编辑2:我的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

编辑3:我在您的nginx配置中发现了一些意外之处,但这可能无关紧要。

您正在使用fastcgi_ignore_client_abort on;,这会导致较旧版本的nginx下的工作进程出现问题。由于我正在运行最近版本的自定义编译,因此我自己没有遇到过这个问题。以下是nginx网站上有关此问题的描述:

在1.0.2中,当fastcgi_ignore_client_abort设置为on时,POST请求处理不正确,这可能导致工作进程崩溃。将fastcgi_ignore_client_abort切换回默认值(off)应解决此问题。


谢谢回复!pm.max_requests是我尝试过很多配置之一,尝试了200到10000之间的许多值。不幸的是,我没有注意到任何变化。我将request_terminate_timeout设置为10,也没有注意到任何变化。有一次它卡在了100%,我停止了http_load,等了几分钟让它平静下来,然后不得不关闭PHP5-FPM,因为它继续消耗CPU。 - Eugene
好的,我尝试了另一个EC2实例以及使用php-fastcgi而不是fpm,虽然文件系统的奇怪锁定已经消失,但问题仍然存在。新服务器在问题发生后恢复了几秒钟,但当出现峰值时,所有内容都超时了。仍在尝试弄清楚可能导致此问题的原因。 - Eugene
6
这个答案已被接受,但没有给出解释。这是否意味着第三个建议解决了问题? - wizonesolutions
@KevinA.Naudé 我的 fpm 消耗了更多的 CPU 使用率,几乎达到了 99.98%,我该如何降低它,如何进行更好的配置。 - Gem
1
@Rathinam,有许多条件可能导致您的PHP CPU使用率达到最大值,这很可能与您的FPM配置以外的因素有关。不幸的是,我目前无法帮助您进一步诊断问题。我建议您发布一个新问题,以提高其在社区中的可见性。祝一切顺利。 - Kevin A. Naudé
显示剩余9条评论

5

我的服务器上的PHP-FPM行为与你的相同,肯定有瓶颈存在。

问题是:如何在Nginx - PHP-FPM - Mysql中找到瓶颈?

最快的方法是:启用PHP-FPM的慢日志。

将以下行添加到您的php-fpm.conf池中,并确保路径存在:

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

通过读取日志回溯,您可以找出为什么PHP-FPM花费了这么多CPU或超时的原因。以下是我的案例:

[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

回溯(backtrace)中提到了这些关键字:

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

我一直在搜索,终于发现Laravel使用随机方法清除过期会话。而且在我的配置中,PHP使用SSD来处理会话。
当会话数量变得“非常大”时,这会使PHP花费更多时间来处理,导致高CPU使用率。
我们可能会遇到许多瓶颈,只有在“调试”时才能知道。
祝您调查愉快。

4

这是一个简单的技巧,但非常有用,可以将处理器使用率降低多达50%,只需要编辑您的php-fpm配置文件:

pm = dynamic

并将其更改为:

pm = ondemand

这个选项对我来说在/usr/local/etc/php/7.1/php-fpm.d/www.conf里。 Mac - Homebrew - James Harrington

2

我现在也遇到了同样的问题,并想指向您这篇文章:

如何确定正在执行的PHP-FPM进程中的脚本

肯定是你的某个PHP脚本引起的。看看能否将失控的进程ID与拖慢你的.php脚本文件联系起来。

有趣的是,这发生在一个一直表现出色的服务器上。我认为可能是WordPress升级(插件或核心)的原因。


哦,顺便说一下,我的问题是通过升级到最新的PHP解决的。我不得不在Ubuntu中更改到一个比LTS更新的新存储库。 - Berto

0

我曾经遇到过同样的问题。我尝试重新配置PHP-FPM和NGINX,但是没有取得很大进展。我们团队中的一位成员禁用了v8js.php(http://php.net/manual/en/book.v8js.php),这解决了问题。我建议禁用任何PHP模块,直到找到问题所在。希望这能帮助到某些人。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接