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

Eug*_*ene 13 php performance nginx performance-testing

我遇到了一个非常奇怪的问题,我不知道如何进一步调试.我有一个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显示了一堆产生了几个CPU的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
Run Code Online (Sandbox Code Playgroud)

然后经过一段时间(可能是一秒到几分钟之间),几个(通常是两个)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
Run Code Online (Sandbox Code Playgroud)

此时一切都会卡住,所有新的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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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"
Run Code Online (Sandbox Code Playgroud)

PHP-FPM慢日志没有显示任何有趣的内容,交换永远不会发生,我没有设法收集有关该问题的任何其他有趣的事实.我经历了许多配置文件更改的迭代,最近的更改

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

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

===更新1 ===

site的配置: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]
Run Code Online (Sandbox Code Playgroud)

===更新3 ===

我们有一个新的Amazon EC2微实例以防万一,以排除可能的硬件问题.此外我现在使用php-fastcgi来排除可能的fpm错误.其他差异很小,我认为唯一改变的是Ubuntu-> Debian.同样的问题仍然发生,除了现在服务器在max_execution_time秒之后设置稍微恢复(然后再次尖峰).

我试着玩一个单独的test.php而且我不确定它是否是同一个问题,但至少top它看起来是一样的.我创建了一个test.php并包含了一堆属于我们框架的库.除了定义类或包含定义类的其他库之外,libs不做任何事情.我检查了APC,所有这些都成功地得到了它.我开始向test.php施加压力,每秒200次请求,过了一段时间后,同样的事情发生了.除了现在我设法得到一些错误说"太多打开文件".它总是不会发生,有时它只是在没有输出错误的情况下开始超时,并且一些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)
Run Code Online (Sandbox Code Playgroud)

因此,到目前为止,我能提出的下一个最好和唯一的解释是,即使APC应该从内存中提取文件,但在内部实现它时,只要调用PHP include-s,它仍然会使用文件描述符.并且要么因为它延迟释放它们,要么在某个不幸的时刻有太多请求在同一时刻到达,系统会运行我们的描述符,并且新到达的HTTP请求会快速堆叠到一个巨大的队列中.我会试着以某种方式测试这个.

Kev*_*udé 10

我运行了一个具有类似配置的网站已有好几个月,没有停机时间.我已经看过你的配置了,看起来还不错.话虽这么说,我不久前做了我的配置.

我会考虑减少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
Run Code Online (Sandbox Code Playgroud)

编辑3:我在你的nginx配置中发现了一些意想不到的东西,但它可能没什么.

您使用的fastcgi_ignore_client_abort on;是在旧版本的nginx下导致工作进程出现问题.我自己没有看到这个问题,因为我正在运行最近版本的自定义编译.这是nginx网站上问题的描述:

在1.0.2中,当fastcgi_ignore_client_abort设置为on时,POST请求未正确处理,这可能导致工作进程进行segfaulting.将fastcgi_ignore_client_abort切换回默认值(关闭)应解决此问题.

  • 这个答案被接受但没有解释.这是否意味着第三个建议修复了什么? (5认同)

min*_*hhq 5

我的服务器上 PHP-FPM 的行为与您相同。肯定在某个地方出现瓶颈。
问题来了:如何找到 Nginx - PHP-FPM - Mysql 上的瓶颈?最快的查找方法是:为 PHP-FPM 启用 Slowlog。
将以下行添加到 php-fpm.conf 池中,并确保该路径存在

request_slowlog_timeout = 10
slowlog = /var/log/php-fpm/slow.$pool.log
Run Code Online (Sandbox Code Playgroud)

通过阅读日志回溯,您可以找出为什么 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
Run Code Online (Sandbox Code Playgroud)

回溯提到了这些关键字:

"cookie" "session" "collectGarbage()" "laravel"
Run Code Online (Sandbox Code Playgroud)

我继续搜索 TADA,Laravel 使用 RANDOM 方法来清除过期的会话。在我的配置中,PHP 使用 SSD 来处理会话。
当会话数变得“非常大”时,这使得 PHP 花费更多时间来处理 => 高 CPU 使用率。

我们可以有很多种瓶颈, 只有当我们“调试”它时才知道它。

好好调查一下。