php-cgi进程占用cpu资源过大原因分析及解决

一,开启日志记录,为以后排查做准备

1.1 开启php-fpm.conf的错误日志和慢执行日志和常规日志, 采样一个小时,就可以根据这些日志的内容进行分析问题
error_log = /tmp/error.log //错误日志
access.log = /tmp/access.$pool.log //常规日志,记录每次访问时间,记录不同参数,以防止恶意攻击,后面会详细解析
access.format = “%R – %u %t \”%m %r%Q%q\” %s %f %{mili}d %{kilo}M %{system}C%%”
slowlog = /tmp/slow.$pool.log //满查询日志记录
request_slowlog_timeout = 3s //慢执行超时时间,可以设置为1秒
1.2 慢查询日志会以堆栈的形式打印每个脚本执行过程中耗时较长的地方,格式如下(可以详细查看我以前发表的PHP慢日志的分析)
[日期时间] [pool www] pid 进程号
script_filename = 脚本文件
[0x00007f2d286c2790] replace() /xxx/Plugin.php:72
[0x00007fff78ab00f0] replace() unknown:0
[0x00007f2d286c2420] call_user_func_array() /xxx/Plugin.php:489
[0x00007fff78ab0430] __call() unknown:0
[0x00007f2d286c1f78] contentEx() /xxx/Abstract/Contents.php:141
[0x00007f2d286c1b78] ___content() /xxx/Widget.php:385
[0x00007f2d286c10f8] +++ dump failed

1.3 使用ll /proc/进程号/fd/ 查看,目前PHP进程在操作什么文件,
使用strace -o /tmp/output.txt -T -tt -F -e trace=all -p <进程号> 来跟踪进程(可查看我以前发表的strace命令的使用)
[[email protected] www]# cat /tmp/output.txt
61905 18:00:40.169437 epoll_wait(8, {}, 1, 409) = 0 <0.410078>
61905 18:00:40.579997 getsockopt(7, SOL_TCP, TCP_INFO, “\n\0\0\0\0\0\0\[email protected]\17\0\0\0\0\0\30\2\0\0\0\0\0\0\0\0\0\0\200\0\0\0″…, [104]) = 0 <0.000327>
61905 18:00:40.580786 epoll_wait(8, {}, 1, 1000) = 0 <1.001902>
61905 18:00:41.583271 getsockopt(7, SOL_TCP, TCP_INFO, “\n\0\0\0\0\0\0\[email protected]\17\0\0\0\0\0\30\2\0\0\0\0\0\0\0\0\0\0\200\0\0\0″…, [104]) = 0 <0.000361>
61905 18:00:41.585020 epoll_wait(8, {}, 1, 999) = 0 <1.001523>
61905 18:00:42.587037 getsockopt(7, SOL_TCP, TCP_INFO, “\n\0\0\0\0\0\0\[email protected]\17\0\0\0\0\0\30\2\0\0\0\0\0\0\0\0\0\0\200\0\0\0″…, [104]) = 0 <0.000408>

二,结合上述的日志,分析可能出现的问题

2.1 php错误日志中,存在大量的常规错误,例如mysql使用了事务导致死锁
2.2 php慢查询日志可以知道那些函数比较耗时,可以考虑使用扩展来实现解决耗时问题, 也有可能是代码中大量使用了file_get_contents等默认不会超时的函数
*file_get_contents一步就做完了打开,读取,关闭的三个动作,过程相当自动化,并且可以读取远程内容,非常方便,在网络状况差的情况下,可能会导致程序执行陷入停滞或者过慢,
因为不停的重试和等待PHP进程本身的超时才会退出。
*这个问题还可以根据跟踪PHP-FPM进程知道,如果存在大量的epoll或select超时
2.3 查询TCP连接是否出现大量TIME_WAIT,HTTP协议1.1版规定default行为是Keep-Alive,
就是会重用TCP连接传输多个请求/响应, 还有就是从nginx到php-fpm的原地址都是一样,TCP连接就会受限制,因为频繁的TCP连接建立和关闭,会在服务器上留下TIME_WAIT状态,
端口一旦进入服务器的TIME_WAIT黑名单,就会产生相当大的超时于等待,甚至阻塞等待
*详细可以查询TIME_WAIT对http的影响一文

三,排查攻击问题

*php是人类的一个伟大的东西,但不代表他永远不会有bugs, 想了解可以去bugs.php.net查看
3.1 根据常规日志,分析是否存在恶意请求, 例如超大表达的哈希攻击,我们查看PHP的数组的实现原理可以知道,它是一个hash表, 包括$_POST,$_GET, 哈希表其实就是一个数组,每个元素是一个链表,
当存在一个恶意的post,post大量的a[]=1&a[]=1&a[]=1&a[]=1&…这种字段,会导致哈希碰撞产生一个超大链表,从而导致效率严重下降

3.2 php-5的PHP解析multipart/form-datahttp请求的body part请求头时,重复拷贝字符串导致DOS。远程攻击者通过发送恶意构造的multipart/form-data请求,导致服务器CPU资源被耗尽,从而远程DOS服务器。
*此bugs比较新,是今年年中的bugs,估计还存在大量的服务器并没有安装补丁(PHP5的严重bug, 其实就是一个没有换行符导致的惨剧)

四,系统优化方面
4.1 不是进程开得越多越好; 拿着16核的CPU, 开着100多个PHP-FPM进程+100多个nginx进程, 纯属装逼; cpu在切换进程的时候不用力吗?
4.2 如果代码和系统的优化都达到最佳状态;可以考虑使用xcache或者apc等进行opcode优化,从而不需要每次都去解析PHP脚本,直接缓存中间代码,可以提升数十倍的性能.

一般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. 程序中存在过度耗时且不可能完成的操作(还是程序的问题)

没有对传入的参数作任何初步检查,而且设置了永不超时,并且使用readfile一次读取超大文件,就可能存在以下问题:
 A. 以http方式读取远程附件过度耗时

B. FTP无法连接时,如何及时反馈出错误?

C. readfile是一次性读取文件加载到内存中并输出,当文件过大时,内存消耗惊人

根据实验发现采用readfile一次性读取,内存消耗会明显增加,但是CPU的利用率会下降较多。如果采用分段读取的方式,内存消耗会稍微下降,而CPU占用却会明显上升。

以下是我逐步整理的故障排除步骤:

1. 得到占用cpu资源过多的php-cgi进程的pid(进程id), 使用top命令即可,如下:

经过上图,我们发现,有两个php-cgi进程的cpu资源占用率过高,pid分别是10059,11570,这一般都是程序优化不够造成,如何定位问题的php程序位置?

2. 找出进程所使用的文件

/proc/文件系统保存在内存中,主要保存系统的状态,关键配置等等,而/proc/目录下有很多数字目录,就是进程的相关信息,如下图,我们看看进程10059正在使用哪些文件?

[[email protected] lib]# ll /proc/10059/fd

显然,使用了/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文件中

如果是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

时间: 2024-10-17 21:53:04

php-cgi进程占用cpu资源过大原因分析及解决的相关文章

PHP CGI 进程占用CPU过高导致CPU使用达到100%的另类原因

由于使用的华为云的CDN加速,结果发现我的阿里云服务器突然卡顿,网页打开极慢.登陆华为云CDN管理后台发现最高带宽占用30M,流量短时间内达到10GB以上,这么大的流量我的服务器肯定扛不住啊.于是还跟华为云进行了一个撕逼,然后果断弃了华为云. 但是更换了其他CDN或者WAF之后,CPU占用依然居高不下,网上找了很多办法都不管用. 看了下是 PHP CGI 进程占用CPU最多,而且经过检测发现是 浏览器内核检测 网站的 PHP CGI 占用最高,其他的很少.然而看第三方网站统计,并没有很大的访问量

在LIUNX服务器上找出web项目中占用cpu资源最多的线程的排查方法

在这里对linux下.sun(oracle) JDK的线程资源占用问题的查找步骤做一个小结:linux环境下,当发现java进程占用CPU资源很高,且又要想更进一步查出哪一个java线程占用了CPU资源时,按照以下步骤进行查找: 第一步:登陆到web服务所在的liunx服务器,利用top命令获取java的cpu使用率 第二步: 如上图所示,java的进程id为'3260',接下来用top命令单独对这个进程中的所有线程作监视:top -p 3260 -H 第三步: 如上图所示,linux下,所有的

java:找出占用CPU资源最多的那个线程(HOW TO)

在这里对linux下.sun(oracle) JDK的线程资源占用问题的查找步骤做一个小结:linux环境下,当发现java进程占用CPU资源很高,且又要想更进一步查出哪一个java线程占用了CPU资源时,按照以下步骤进行查找: 先用top命令找出占用资源厉害的java进程id,如: 如上图所示,java的进程id为'12377',接下来用top命令单独对这个进程中的所有线程作监视: ? 1 top -p 12377 -H 如图: 如上图所示,linux下,所有的java内部线程,其实都对应了一

Java虚拟机六:Java进程占用cpu过高问题分析

在平时开发过程中,经常会碰到Java进程占用cpu过高的现象,本篇将简单记录一下自己分析该类问题的步骤. 1.使用 top -p <pid> 命令(<pid>为Java进程的id号)查看Java进程的cpu占用: 该Java进程占用cpu达到92.2%. 2.使用 top -Hp <pid>  命令(<pid>为Java进程的id号)查看该Java进程内所有线程的资源占用情况(按shft+p按照cpu占用进行排序,按shift+m按照内存占用进行排序)此处按

Apache服务器httpd.exe进程占用cpu超过50%的解决方法

httpd.exe进程占用cpu超过50%,关闭掉Apache服务,cpu应用率立刻下降到0.  重新启动Apache又出现占用cpu高的情况.  原因是:httpd.exe和防火墙配置有冲突. 解决方法如下: 1.网上邻居->本地链接->属性->internet协议(TCP/IP)->属性->高级->wins标签->去掉起用LMhosts查询前的勾. 2.控制面版->windows防火墙->高级标签->本地链接设置->服务的标签里勾选安全

nova-conductor单个进程占用CPU 100%

nova-conductor进程在运行时,其中单个进程会周期性的占用CPU 100%的使用率,周期大约2分钟.经调试和排查,发现原因在于nova-conductor在执行某一数据库操作时,请求数据量巨大, 仅数据库查找耗时10s,返回数据大小在2MB.导致数据在进行序列化和解序列化时耗尽CPU,并持续时间较长.详情如下: 操作请求:object_class_action 请求参数:{u'objver': u'1.6', u'objmethod': u'get_by_filters', u'arg

Win10 WMI Provider Host进程占用CPU过高的解决方法

在使用系统过程中,偶尔会出现由于某些进程而导致CPU等硬件资源占用过多,进而出现系统卡顿的情况.一个Win10用户发现“WMI Provider Host“占用了过多CPU资源导致系统卡顿,该如何解决这个问题呢? 解决方法: 可以尝试关闭Windows防火墙服务来解决这个问题. 1.按住win+R,输入services.msc,回车. 2.在服务里面找到Windows Firewall,双击,在启动类型中选择“禁止”. 3.重启Win10系统,然后测试问题是否得到解决. 有的用户不知道是哪个进程

linux下查找java进程占用CPU过高原因

1. 查找进程 top查看进程占用资源情况 明显看出java的两个进程22714,12406占用过高cpu. 2.查找线程 使用top -H -p <pid>查看线程占用情况 3.查找java的堆栈信息 将线程id转换成十六进制 #printf %x 15664 #3d30 然后再使用jstack查询线程的堆栈信息 语法:jstack <pid> | grep -a 线程id(十六进制) jstack <pid> | grep -a 3d30 这样就找出了有问题的代码了

java进程占用cpu过高分析是哪些线程

拿hbase基准测试列子来分析哪些线程使用比较高的cpu,环境是linux,基准测试命令: hbase org.apache.hadoop.hbase.PerformanceEvaluation  --rows=500000 --nomapred --presplit=5 --writeToWAL=true randomWrite 5 首先查看占用cpu最高的进程和线程id,执行命令: [[email protected] logs]$ ps Hh -eo pid,tid,pcpu | sort