PHP-CGI进程CPU 100% 与 file_get_contents 函数的关系分析


Posted in PHP onAugust 15, 2011

后来,我通过跟踪发现,这类情况的出现,跟 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 配置文件中的以下参数: 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>

默认值为 0 秒,也就是说,PHP 脚本会一直执行下去。这样,当所有的 php-cgi 进程都卡在 file_get_contents() 函数时,这台 Nginx+PHP 的 WebServer 已经无法再处理新的 PHP 请求了,Nginx 将给用户返回“502 Bad Gateway”。修改该参数,设置一个 PHP 脚本最大执行时间是必要的,但是,治标不治本。例如改成 30s,如果发生 file_get_contents() 获取网页内容较慢的情况,这就意味着 150 个 php-cgi 进程,每秒钟只能处理 5 个请求,WebServer 同样很难避免“502 Bad Gateway”。

要做到彻底解决,只能让 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); 
?>

当然,导致 php-cgi 进程 CPU 100% 的原因不只有这一种,那么,怎么确定是 file_get_contents() 函数导致的呢?

首先,使用 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 
10709 www 16 0 359m 28m 17m R 96.8 0.4 0:11.34 php-cgi 
10745 www 18 0 360m 24m 14m R 94.8 0.3 0:39.51 php-cgi 
10707 www 18 0 360m 25m 14m S 77.4 0.3 0:33.48 php-cgi 
10782 www 20 0 360m 26m 15m R 75.5 0.3 0:10.93 php-cgi 
10708 www 25 0 360m 22m 12m R 69.7 0.3 0:45.16 php-cgi 
10683 www 25 0 362m 28m 15m R 54.2 0.4 0:32.65 php-cgi 
10711 www 25 0 360m 25m 15m R 52.2 0.3 0:44.25 php-cgi 
10688 www 25 0 359m 25m 15m R 38.7 0.3 0:10.44 php-cgi 
10719 www 25 0 360m 26m 16m R 7.7 0.3 0:40.59 php-cgi

找其中一个 CPU 100% 的 php-cgi 进程的 PID,用以下命令跟踪一下:

strace -p 10747 
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0}) 
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout) 
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0}) 
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout) 
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0}) 
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout) 
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0}) 
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout) 
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0}) 
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout) 
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0}) 
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout) 
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0}) 
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout) 
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0}) 
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout) 
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0}) 
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout) 
select(7, [6], [6], [], {15, 0}) = 1 (out [6], left {15, 0}) 
poll([{fd=6, events=POLLIN}], 1, 0) = 0 (Timeout)

那么,就可以确定是 file_get_contents() 导致的问题了。

PHP 相关文章推荐
NOD32 v2.70.32 简体中文封装版 提供下载了
Feb 27 PHP
8个出色的WordPress SEO插件收集
Feb 26 PHP
php生成静态文件的多种方法分享
Jul 17 PHP
使用php清除bom示例
Mar 03 PHP
让codeigniter与swfupload整合的最佳解决方案
Jun 12 PHP
PHP使用glob函数遍历目录或文件夹的方法
Dec 16 PHP
jQuery+PHP实现的掷色子抽奖游戏实例
Jan 04 PHP
php实现遍历多维数组的方法
Nov 25 PHP
zen cart实现订单中增加paypal中预留电话的方法
Jul 12 PHP
一个简单安全的PHP验证码类、PHP验证码
Sep 24 PHP
thinkPHP自动验证、自动添加及表单错误问题分析
Oct 17 PHP
win7 wamp 64位 php环境开启curl服务遇到的问题及解决方法
Sep 16 PHP
11个PHP 分页脚本推荐
Aug 15 #PHP
PHP版国家代码、缩写查询函数代码
Aug 14 #PHP
PHP动态创建Web站点的方法
Aug 14 #PHP
php程序的国际化实现方法(利用gettext)
Aug 14 #PHP
PHP排序之二维数组的按照字母排序实现代码
Aug 13 #PHP
php中使用Curl、socket、file_get_contents三种方法POST提交数据
Aug 12 #PHP
PHP简洁函数小结
Aug 12 #PHP
You might like
php Http_Template_IT类库进行模板替换
2009/03/19 PHP
php 常用类整理
2009/12/23 PHP
分享五个PHP7性能优化提升技巧
2015/12/07 PHP
PHP实现基于图的深度优先遍历输出1,2,3...n的全排列功能
2017/11/10 PHP
php中try catch捕获异常实例详解
2020/08/06 PHP
Firefox window.close()的使用注意事项
2009/04/11 Javascript
jquery图片不完全按比例自动缩小的简单代码
2013/07/29 Javascript
nodejs实现的一个简单聊天室功能分享
2014/12/06 NodeJs
基于jquery实现无限级树形菜单
2016/03/22 Javascript
JavaScript随机生成颜色的方法
2016/10/15 Javascript
laravel5.3 vue 实现收藏夹功能实例详解
2018/01/21 Javascript
优雅地使用loading(推荐)
2019/04/20 Javascript
基于iview-admin实现动态路由的示例代码
2019/10/02 Javascript
VueCli4项目配置反向代理proxy的方法步骤
2020/05/17 Javascript
浏览器JavaScript调试功能无法使用解决方案
2020/09/18 Javascript
uni-app使用countdown插件实现倒计时
2020/11/01 Javascript
WebPack工具运行原理及入门教程
2020/12/02 Javascript
使用python 获取进程pid号的方法
2014/03/10 Python
python虚拟环境virualenv的安装与使用
2016/12/18 Python
利用numpy实现一、二维数组的拼接简单代码示例
2017/12/15 Python
Python数据拟合与广义线性回归算法学习
2017/12/22 Python
Python中str.join()简单用法示例
2018/03/20 Python
python多行字符串拼接使用小括号的方法
2020/03/19 Python
python实现控制COM口的示例
2019/07/03 Python
Python+PyQt5实现灭霸响指功能
2020/05/25 Python
python 图像增强算法实现详解
2021/01/24 Python
跨域修改iframe页面内容详解
2019/10/31 HTML / CSS
amazeui时间组件的实现示例
2020/08/18 HTML / CSS
阿联酋团购网站:Groupon阿联酋
2016/10/14 全球购物
哈曼俄罗斯官方网上商店:Harman.club
2020/07/24 全球购物
2014年学生会主席工作总结
2014/11/07 职场文书
2015小学教师德育工作总结
2015/05/12 职场文书
升学宴学生致辞
2015/09/29 职场文书
Python机器学习三大件之一numpy
2021/05/10 Python
Python中zipfile压缩包模块的使用
2021/05/14 Python
Python Matplotlib库实现画局部图
2021/11/17 Python