php-cgi进程占用cpu资源过大原因分析及解决(找出有问题的linux进程)
2013-06-04 16:12
781 查看
服务器环境:redhat linux 5.5 , nginx , phpfastcgi
在此环境下,一般php-cgi运行是非常稳定的,但也遇到过php-cgi占用太多cpu资源而导致服务器响应过慢,我所遇到的php-cgi进程占用cpu资源过多的原因有:
1. 一些php的扩展与php版本兼容存在问题,实践证明 eAccelerater与某些php版本兼容存在问题,具体表现时启动php-cgi进程后,运行10多分钟,奇慢无比,但静态资源访问很快,服务器负载也很正常(说明nginx没有问题,而是php-cgi进程的问题),解决办法就是从php.ini中禁止掉eAccelerater模块,再重启php-cgi进程即可
2. 程序中可能存在死循环,导致服务器负载超高(使用top指令查看负载高达100+), 需要借助Linux的proc虚拟文件系统找到具体的问题程序
3. php程序不合理使用session , 这个发生在开源微博记事狗程序上,具体表现是有少量php-cgi进程(不超过10个)的cpu使用率达98%以上, 服务器负载在4-8之间,这个问题的解决,仍然需要借助Linux的proc文件系统找出原因。
4. 程序中存在过度耗时且不可能完成的操作(还是程序的问题),例如discuz x 1.5的附件下载功能: source/module/forum/forum_attachement.php中的定义
function getremotefile($file) {
global $_G;
@set_time_limit(0);
if(!@readfile($_G['setting']['ftp']['attachurl'].'forum/'.$file)) {
$ftp = ftpcmd('object');
$tmpfile = @tempnam($_G['setting']['attachdir'], '');
if($ftp->ftp_get($tmpfile, 'forum/'.$file, FTP_BINARY)) {
@readfile($tmpfile);
@unlink($tmpfile);
} else {
@unlink($tmpfile);
return FALSE;
}
}
return TRUE;
}
没有对传入的参数作任何初步检查,而且设置了永不超时,并且使用readfile一次读取超大文件,就可能存在以下问题:
A. 以http方式读取远程附件过度耗时
B. FTP无法连接时,如何及时反馈出错误?
C. readfile是一次性读取文件加载到内存中并输出,当文件过大时,内存消耗惊人
根据实验发现采用readfile一次性读取,内存消耗会明显增加,但是CPU的利用率会下降较多。如果采用分段读取的方式,内存消耗会稍微下降,而CPU占用却会明显上升。
对discuz x 1.5的这个bug较好解决方法就是后台重新正确设置远程附件参数。
以下是我逐步整理的故障排除步骤:
1. 得到占用cpu资源过多的php-cgi进程的pid(进程id), 使用top命令即可,如下图:
经过上图,我们发现,有两个php-cgi进程的cpu资源占用率过高,pid分别是10059,11570,这一般都是程序优化不够造成,如何定位问题的php程序位置?
2. 找出进程所使用的文件
/proc/文件系统保存在内存中,主要保存系统的状态,关键配置等等,而/proc/目录下有很多数字目录,就是进程的相关信息,如下图,我们看看进程10059正在使用哪些文件?
显然,使用了/home/tmp/sess_*文件,这明显是PHP的session文件, 我们查看这个session文件的内容为:view_time|123333312412
到这里,我们已经可以怀疑是由于php程序写入一个叫view_time的session项而引起, 那么剩余的事件就是检查包含view_time的所有php文件,然后修改之(比如改用COOKIE),这实话, 这个view_time并非敏感数据,仅仅记录用户最后访问时间,实在没必要使用代价巨大的session, 而应该使用cookie。
3. 找出有问题的程序,修改之
使用vi编辑以下shell程序(假设网站程序位于/www目录下)
#!/bin/bash
find /www/ -name "*.php" > list.txt
f=`cat ./list.txt`
for n in $f
do
r=`egrep 'view_time' $n`
if [ ! "$r" = "" ] ; then
echo $n
fi
done
运行这个shell程序,将输出包含有view_time的文件, 对记事狗微博系统,产生的问题位于modules/topic.mod.class文件中
以下是miltonzhong我本人解决的一个过程,供以后参照
我和老大的谈话:
27927 fuyi 19 0 319m 15m 8616 R 67.0 0.2 0:40.16 php-cgi
27956 fuyi 25 0 320m 15m 8444 S 64.6 0.2 0:25.34 php-cgi
27946 fuyi 25 0 319m 15m 8532 S 57.6 0.2 0:28.13 php-cgi
27929 fuyi 25 0 319m 14m 8156 R 51.0 0.2 0:19.43 php-cgi
27940 fuyi 16 0 319m 15m 8372 S 43.5 0.2 0:28.09 php-cgi
27926 fuyi 18 0 320m 15m 8432 S 38.0 0.2 0:24.60 php-cgi
27922 fuyi 16 0 320m 16m 9200 S 32.4 0.2 0:24.65 php-cgi
27938 fuyi 16 0 319m 15m 8696 R 19.8 0.2 0:42.01 php-cgi
思考:
可以从哪些地方考虑 2013-06-04 15:30:27
可能是远程获取数据超时导致 2013-06-04 15:30:38
也可能是死循环 2013-06-04 15:30:40
看连接数和是否超时 2013-06-04 15:31:24
我的mysqld和web不是在同一台机器的 2013-06-04 15:31:31
哦。好 2013-06-04 15:33:41
那应该是经常超时了 2013-06-04 15:35:20
有时候同一台服务器放全部服务还快一点感觉 2013-06-04 15:35:52
查询不多肯定是一台快 2013-06-04 15:36:10
如果是内网也可以分开
经过谈话,有所感想,于是试着解决
[root@fuyi02 olwoo]# ps -aux | grep php
Warning: bad syntax, perhaps a bogus '-'? See /usr/share/doc/procps-3.2.7/FAQ
root 2150 0.0 0.0 325276 5584 ? Ss 16:26 0:00 /usr/local/webserver/php/bin/php-cgi --fpm --fpm-config /usr/local/webserver/php/etc/php-fpm.conf
fuyi 2151 9.9 0.1 327864 15940 ? S 16:26 1:05 /usr/local/webserver/php/bin/php-cgi --fpm --fpm-config /usr/local/webserver/php/etc/php-fpm.conf
fuyi 2152 9.3 0.1 327612 15700 ? S 16:26 1:01 /usr/local/webserver/php/bin/php-cgi --fpm --fpm-config /usr/local/webserver/php/etc/php-fpm.conf
fuyi 2153 10.8 0.2 327612 16804 ? S 16:26 1:11 /usr/local/webserver/php/bin/php-cgi --fpm --fpm-config /usr/local/webserver/php/etc/php-fpm.conf
fuyi 2154 9.7 0.1 327864 15460 ? S 16:26 1:03 /usr/local/webserver/php/bin/php-cgi --fpm --fpm-config /usr/local/webserver/php/etc/php-fpm.conf
strace命令跟踪下看看这个进程在做什么东西
strace -p 2185
出现大量
poll([{fd=4, events=POLLIN}], 1, 0) = 0 (Timeout)
select(5, [4], [4], [], {15, 0}) = 1 (out [4], left {15, 0})
poll([{fd=4, events=POLLIN}], 1, 0) = 0 (Timeout)
select(5, [4], [4], [], {15, 0}) = 1 (out [4], left {15, 0})
poll([{fd=4, events=POLLIN}], 1, 0) = 0 (Timeout)
可以看出,这个进程不断的超时,到底为何会超时呢???看来需要从php-cgi的日志中查找问题了,由于原来php-fpm.conf配置的超时时间为0,也就是不设置超时时间。于是先将php-fpm.conf的超时时间设置成5s,然后超过5s的php-cgi的请求就会记录到php的慢日志中
慢日志设置:
<value name="request_slowlog_timeout">3s</value>
<value name="slowlog">logs/slow.log</value>
设置完成,利用命令/usr/local/php/sbin/php-fpm restart重启php-fpm,过一会查看slow.log的内容发现很多如下内容:
script_filename = /data/htdocs/bbs.hrloo.com/apl.php
[0x00007fffb060fd70] file_get_contents() /data/htdocs/bbs.hrloo.com/apl.php:10
超时时间:
<value name="request_terminate_timeout">0s</value>
这个参数的默认值为0秒,意为永不超时
根据以上,解决方法:
ulimit -SHn 102400 (友新解决的)
首页一定要做成伪静态 ,或者缓存
最终解决方法:PHP函数问题导致CPU飙升
从
strace -p 2185
出现大量
poll([{fd=4, events=POLLIN}], 1, 0) = 0 (Timeout)
select(5, [4], [4], [], {15, 0}) = 1 (out [4], left {15, 0})
poll([{fd=4, events=POLLIN}], 1, 0) = 0 (Timeout)
select(5, [4], [4], [], {15, 0}) = 1 (out [4], left {15, 0})
poll([{fd=4, events=POLLIN}], 1, 0) = 0 (Timeout)
可以看出是file_get_contents()导致的问题
函数解释:就是获取文件内容或者网址内容,获取不到,就一直卡死了,导致耗费资源,这个是ecmall的核心文件。首页调用了。
工具: lsof 也是强大的调试工具
如果是mysql或其他服务导致,可以查看错误日志
如mysql
tail /usr/local/mysql/err_log/mysqlerr.log -f
[ERROR] /usr/local/mysql/libexec/mysqld: Sort aborted
或者内存不够,可以用以下方法迅速找出占用内存大的进程:
ps -e -o "%C : %p : %z : %a"|sort -k5 -nr
在此环境下,一般php-cgi运行是非常稳定的,但也遇到过php-cgi占用太多cpu资源而导致服务器响应过慢,我所遇到的php-cgi进程占用cpu资源过多的原因有:
1. 一些php的扩展与php版本兼容存在问题,实践证明 eAccelerater与某些php版本兼容存在问题,具体表现时启动php-cgi进程后,运行10多分钟,奇慢无比,但静态资源访问很快,服务器负载也很正常(说明nginx没有问题,而是php-cgi进程的问题),解决办法就是从php.ini中禁止掉eAccelerater模块,再重启php-cgi进程即可
2. 程序中可能存在死循环,导致服务器负载超高(使用top指令查看负载高达100+), 需要借助Linux的proc虚拟文件系统找到具体的问题程序
3. php程序不合理使用session , 这个发生在开源微博记事狗程序上,具体表现是有少量php-cgi进程(不超过10个)的cpu使用率达98%以上, 服务器负载在4-8之间,这个问题的解决,仍然需要借助Linux的proc文件系统找出原因。
4. 程序中存在过度耗时且不可能完成的操作(还是程序的问题),例如discuz x 1.5的附件下载功能: source/module/forum/forum_attachement.php中的定义
function getremotefile($file) {
global $_G;
@set_time_limit(0);
if(!@readfile($_G['setting']['ftp']['attachurl'].'forum/'.$file)) {
$ftp = ftpcmd('object');
$tmpfile = @tempnam($_G['setting']['attachdir'], '');
if($ftp->ftp_get($tmpfile, 'forum/'.$file, FTP_BINARY)) {
@readfile($tmpfile);
@unlink($tmpfile);
} else {
@unlink($tmpfile);
return FALSE;
}
}
return TRUE;
}
没有对传入的参数作任何初步检查,而且设置了永不超时,并且使用readfile一次读取超大文件,就可能存在以下问题:
A. 以http方式读取远程附件过度耗时
B. FTP无法连接时,如何及时反馈出错误?
C. readfile是一次性读取文件加载到内存中并输出,当文件过大时,内存消耗惊人
根据实验发现采用readfile一次性读取,内存消耗会明显增加,但是CPU的利用率会下降较多。如果采用分段读取的方式,内存消耗会稍微下降,而CPU占用却会明显上升。
对discuz x 1.5的这个bug较好解决方法就是后台重新正确设置远程附件参数。
以下是我逐步整理的故障排除步骤:
1. 得到占用cpu资源过多的php-cgi进程的pid(进程id), 使用top命令即可,如下图:
经过上图,我们发现,有两个php-cgi进程的cpu资源占用率过高,pid分别是10059,11570,这一般都是程序优化不够造成,如何定位问题的php程序位置?
2. 找出进程所使用的文件
/proc/文件系统保存在内存中,主要保存系统的状态,关键配置等等,而/proc/目录下有很多数字目录,就是进程的相关信息,如下图,我们看看进程10059正在使用哪些文件?
显然,使用了/home/tmp/sess_*文件,这明显是PHP的session文件, 我们查看这个session文件的内容为:view_time|123333312412
到这里,我们已经可以怀疑是由于php程序写入一个叫view_time的session项而引起, 那么剩余的事件就是检查包含view_time的所有php文件,然后修改之(比如改用COOKIE),这实话, 这个view_time并非敏感数据,仅仅记录用户最后访问时间,实在没必要使用代价巨大的session, 而应该使用cookie。
3. 找出有问题的程序,修改之
使用vi编辑以下shell程序(假设网站程序位于/www目录下)
#!/bin/bash
find /www/ -name "*.php" > list.txt
f=`cat ./list.txt`
for n in $f
do
r=`egrep 'view_time' $n`
if [ ! "$r" = "" ] ; then
echo $n
fi
done
运行这个shell程序,将输出包含有view_time的文件, 对记事狗微博系统,产生的问题位于modules/topic.mod.class文件中
以下是miltonzhong我本人解决的一个过程,供以后参照
我和老大的谈话:
27927 fuyi 19 0 319m 15m 8616 R 67.0 0.2 0:40.16 php-cgi
27956 fuyi 25 0 320m 15m 8444 S 64.6 0.2 0:25.34 php-cgi
27946 fuyi 25 0 319m 15m 8532 S 57.6 0.2 0:28.13 php-cgi
27929 fuyi 25 0 319m 14m 8156 R 51.0 0.2 0:19.43 php-cgi
27940 fuyi 16 0 319m 15m 8372 S 43.5 0.2 0:28.09 php-cgi
27926 fuyi 18 0 320m 15m 8432 S 38.0 0.2 0:24.60 php-cgi
27922 fuyi 16 0 320m 16m 9200 S 32.4 0.2 0:24.65 php-cgi
27938 fuyi 16 0 319m 15m 8696 R 19.8 0.2 0:42.01 php-cgi
思考:
可以从哪些地方考虑 2013-06-04 15:30:27
可能是远程获取数据超时导致 2013-06-04 15:30:38
也可能是死循环 2013-06-04 15:30:40
看连接数和是否超时 2013-06-04 15:31:24
我的mysqld和web不是在同一台机器的 2013-06-04 15:31:31
哦。好 2013-06-04 15:33:41
那应该是经常超时了 2013-06-04 15:35:20
有时候同一台服务器放全部服务还快一点感觉 2013-06-04 15:35:52
查询不多肯定是一台快 2013-06-04 15:36:10
如果是内网也可以分开
经过谈话,有所感想,于是试着解决
[root@fuyi02 olwoo]# ps -aux | grep php
Warning: bad syntax, perhaps a bogus '-'? See /usr/share/doc/procps-3.2.7/FAQ
root 2150 0.0 0.0 325276 5584 ? Ss 16:26 0:00 /usr/local/webserver/php/bin/php-cgi --fpm --fpm-config /usr/local/webserver/php/etc/php-fpm.conf
fuyi 2151 9.9 0.1 327864 15940 ? S 16:26 1:05 /usr/local/webserver/php/bin/php-cgi --fpm --fpm-config /usr/local/webserver/php/etc/php-fpm.conf
fuyi 2152 9.3 0.1 327612 15700 ? S 16:26 1:01 /usr/local/webserver/php/bin/php-cgi --fpm --fpm-config /usr/local/webserver/php/etc/php-fpm.conf
fuyi 2153 10.8 0.2 327612 16804 ? S 16:26 1:11 /usr/local/webserver/php/bin/php-cgi --fpm --fpm-config /usr/local/webserver/php/etc/php-fpm.conf
fuyi 2154 9.7 0.1 327864 15460 ? S 16:26 1:03 /usr/local/webserver/php/bin/php-cgi --fpm --fpm-config /usr/local/webserver/php/etc/php-fpm.conf
strace命令跟踪下看看这个进程在做什么东西
strace -p 2185
出现大量
poll([{fd=4, events=POLLIN}], 1, 0) = 0 (Timeout)
select(5, [4], [4], [], {15, 0}) = 1 (out [4], left {15, 0})
poll([{fd=4, events=POLLIN}], 1, 0) = 0 (Timeout)
select(5, [4], [4], [], {15, 0}) = 1 (out [4], left {15, 0})
poll([{fd=4, events=POLLIN}], 1, 0) = 0 (Timeout)
可以看出,这个进程不断的超时,到底为何会超时呢???看来需要从php-cgi的日志中查找问题了,由于原来php-fpm.conf配置的超时时间为0,也就是不设置超时时间。于是先将php-fpm.conf的超时时间设置成5s,然后超过5s的php-cgi的请求就会记录到php的慢日志中
慢日志设置:
<value name="request_slowlog_timeout">3s</value>
<value name="slowlog">logs/slow.log</value>
设置完成,利用命令/usr/local/php/sbin/php-fpm restart重启php-fpm,过一会查看slow.log的内容发现很多如下内容:
script_filename = /data/htdocs/bbs.hrloo.com/apl.php
[0x00007fffb060fd70] file_get_contents() /data/htdocs/bbs.hrloo.com/apl.php:10
超时时间:
<value name="request_terminate_timeout">0s</value>
这个参数的默认值为0秒,意为永不超时
根据以上,解决方法:
ulimit -SHn 102400 (友新解决的)
首页一定要做成伪静态 ,或者缓存
最终解决方法:PHP函数问题导致CPU飙升
从
strace -p 2185
出现大量
poll([{fd=4, events=POLLIN}], 1, 0) = 0 (Timeout)
select(5, [4], [4], [], {15, 0}) = 1 (out [4], left {15, 0})
poll([{fd=4, events=POLLIN}], 1, 0) = 0 (Timeout)
select(5, [4], [4], [], {15, 0}) = 1 (out [4], left {15, 0})
poll([{fd=4, events=POLLIN}], 1, 0) = 0 (Timeout)
可以看出是file_get_contents()导致的问题
函数解释:就是获取文件内容或者网址内容,获取不到,就一直卡死了,导致耗费资源,这个是ecmall的核心文件。首页调用了。
工具: lsof 也是强大的调试工具
如果是mysql或其他服务导致,可以查看错误日志
如mysql
tail /usr/local/mysql/err_log/mysqlerr.log -f
[ERROR] /usr/local/mysql/libexec/mysqld: Sort aborted
或者内存不够,可以用以下方法迅速找出占用内存大的进程:
ps -e -o "%C : %p : %z : %a"|sort -k5 -nr
ps -e -o'user,uid,pid,comm,args,pcpu,rsz,vsz,stime'|sort -nrk7|head -1
相关文章推荐
- php-cgi进程占用cpu资源过大原因分析及解决
- php-cgi进程占用cpu资源过多负载高的原因分析及解决步骤
- php-cgi进程占用cpu资源过多负载高的原因分析及解决步骤
- php-cgi进程占用cpu资源过多负载高的原因分析及解决步骤
- php-cgi进程占用cpu资源过多负载高的原因分析及解决步骤
- php-cgi进程占用cpu资源过多负载高的原因分析及解决步骤
- php-cgi进程占用cpu资源过多负载高的原因分析及解决步骤
- 进程占用cpu资源过多负载高的原因分析及解决步骤
- php-cgi占用cpu资源过高的解决方法
- [原]分析Vista导致资源管理器占用CPU资源100%的问题的原因及解决办法
- linux进程资源占用高原因分析命令记录
- 服务器php-cgi.exe进程过多,导致CPU占用100%的解决方法
- Linux下Java进程占用CPU超较高原因分析
- 服务器php-cgi.exe进程过多,导致CPU占用100%的解决方法
- linux进程资源占用高原因分析命令记录
- system进程占用cpu资源过大的原因
- 服务器大量php-cgi.exe进程,导致CPU占用100%的解决
- php-cgi占用cpu资源过高的解决方法
- IIS应用程序池w3wp.exe CPU 占用100% 分析软件,找出具体有问题的ASP程序URL
- (转)Windows Server 2003中的w3wp.exe进程大量占用cpu资源的各种问题解决方法