linux - PHP-CGI 进程 CPU 100% 与 file_get_contents&nbs
(2013-11-19 16:46:15)
标签:
php-cgi进程cpu100与it |
分类: linux那些事 |
[文章作者:张宴 本文版本:v1.0 最后修改:2011.08.05 转载请注明原文链接:http://blog.s135.com/file_get_contents/]
有时候,运行 Nginx、PHP-CGI(php-fpm) Web服务的 Linux 服务器,突然系统负载上升,使用 top 命令查看,很多 php-cgi 进程 CPU 使用率接近100%。后来,我通过跟踪发现,这类情况的出现,跟 PHP 的 file_get_contents() 函数有着密切的关系。
大、中型网站中,基于 HTTP 协议的 API 接口调用,是家常便饭。PHP 程序员们喜欢使用简单便捷的 file_get_contents("http://example.com/") 函数,来获取一个 URL 的返回内容,但是,如果 http://example.com/ 这个网站响应缓慢,file_get_contents()
就会一直卡在那儿,不会超时。
我们知道,在 php.ini 中,有一个参数 max_execution_time 可以设置 PHP 脚本的最大执行时间,但是,在 php-cgi(php-fpm) 中,该参数不会起效。真正能够控制 PHP 脚本最大执行时间的是 php-fpm.conf 配置文件中的以下参数:
默认值为
0 秒,也就是说,PHP 脚本会一直执行下去。这样,当所有的 php-cgi 进程都卡在 file_get_contents()
函数时,这台 Nginx+PHP 的 WebServer 已经无法再处理新的 PHP 请求了,Nginx 将给用户返回“502 Bad
Gateway”。修改该参数,设置一个 PHP 脚本最大执行时间是必要的,但是,治标不治本。例如改成
<value
name="request_terminate_timeout">30s</value>,如果发生
file_get_contents() 获取网页内容较慢的情况,这就意味着 150 个 php-cgi 进程,每秒钟只能处理 5
个请求,WebServer 同样很难避免“502 Bad Gateway”。
要做到彻底解决,只能让 PHP 程序员们改掉直接使用 file_get_contents("http://example.com/") 的习惯,而是稍微修改一下,加个超时时间,用以下方式来实现 HTTP GET 请求。要是觉得麻烦,可以自行将以下代码封装成一个函数。
当然,导致
php-cgi 进程 CPU 100% 的原因不只有这一种,那么,怎么确定是 file_get_contents()
函数导致的呢?
首先,使用 top 命令查看 CPU 使用率较高的 php-cgi 进程。
有时候,运行 Nginx、PHP-CGI(php-fpm) Web服务的 Linux 服务器,突然系统负载上升,使用 top 命令查看,很多 php-cgi 进程 CPU 使用率接近100%。后来,我通过跟踪发现,这类情况的出现,跟 PHP 的 file_get_contents() 函数有着密切的关系。
大、中型网站中,基于 HTTP 协议的 API 接口调用,是家常便饭。PHP 程序员们喜欢使用简单便捷的 file_get_contents("http://example.com/") 函数,来获取一个 URL 的返回内容,但是,如果
我们知道,在 php.ini 中,有一个参数 max_execution_time 可以设置 PHP 脚本的最大执行时间,但是,在 php-cgi(php-fpm) 中,该参数不会起效。真正能够控制 PHP 脚本最大执行时间的是 php-fpm.conf 配置文件中的以下参数:
-
The
timeout (in seconds) for serving a single request after which the worker process will be terminated -
Should
be used when 'max_execution_time' ini option does not stop script execution for some reason -
'0s'
means 'off' -
<value
name="request_terminate_timeout">0s</value>
要做到彻底解决,只能让 PHP 程序员们改掉直接使用 file_get_contents("http://example.com/") 的习惯,而是稍微修改一下,加个超时时间,用以下方式来实现 HTTP GET 请求。要是觉得麻烦,可以自行将以下代码封装成一个函数。
-
<?php
-
$ctx
= stream_context_create(array( -
'http' => array( -
'timeout' => 1 //设置一个超时时间,单位为秒 -
) -
) -
);
-
file_get_contents("http://example.com/",
0, $ctx); -
?>
首先,使用 top 命令查看 CPU 使用率较高的 php-cgi 进程。
top - 10:34:18 up 724 days,
21:01, 3
users, load average: 17.86,
11.16, 7.69
Tasks: 561 total, 15 running,
546 sleeping, 0
stopped, 0 zombie
Cpu(s): 5.9%us, 4.2%sy, 0.0%ni,
89.4%id, 0.2%wa, 0.0%hi, 0.2%si, 0.0%st
Mem: 8100996k
total, 4320108k
used, 3780888k
free, 772572k buffers
Swap: 8193108k
total, 50776k
used, 8142332k
free, 412088k cached
PID
USER PR NI VIRT RES SHR
S %CPU
%MEM TIME+ COMMAND
10747 www
18
0 360m 22m 12m
R 100.6
0.3 0:02.60
php-cgi
Tasks: 561 total,
Cpu(s):
Mem:
Swap:
10747 www