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

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介:

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


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命令的使用)
[root@localhost 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\0@B\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\0@B\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\0@B\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命令即可,如下:

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

    

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

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

[root@web01 lib]# ll /proc/10059/fd


1ed71cd2-253c-3124-85cc-a608ca89b250.jpg

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

本文转自写个博客骗钱博客51CTO博客,原文链接http://blog.51cto.com/dadonggg/1947577如需转载请自行联系原作者


菜鸟东哥

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
28天前
|
存储 Shell Linux
【Shell 命令集合 系统设置 】⭐⭐⭐Linux 限制进程资源 ulimit命令 使用指南
【Shell 命令集合 系统设置 】⭐⭐⭐Linux 限制进程资源 ulimit命令 使用指南
37 0
|
3月前
|
Linux
|
2月前
|
机器学习/深度学习 编解码 缓存
CPU型号分析避坑指南——2、游戏电脑与办公电脑CPU该如何选择
CPU型号分析避坑指南——2、游戏电脑与办公电脑CPU该如何选择
50 0
|
3月前
|
Linux 调度
linux中进程与cpu核的绑定
linux中进程与cpu核的绑定
67 0
|
23天前
|
存储 监控 Linux
Linux 使用getrusage系统调用获取cpu信息:一个C++实例分析
Linux 使用getrusage系统调用获取cpu信息:一个C++实例分析
48 0
|
23天前
|
存储 算法 Linux
【Linux 系统标准 进程资源】Linux 创建一个最基本的进程所需的资源分析,以及线程资源与之的差异
【Linux 系统标准 进程资源】Linux 创建一个最基本的进程所需的资源分析,以及线程资源与之的差异
25 0
|
消息中间件 监控 安全
探究如何在Linux系统中修改进程资源限制:四种方法调整进程限制,让你的系统高效运行(包含应用层getrlimit和setrlimit API)
探究如何在Linux系统中修改进程资源限制:四种方法调整进程限制,让你的系统高效运行(包含应用层getrlimit和setrlimit API)
43 0
|
2月前
|
网络协议 Linux
【系统DFX】如何诊断占用过多 CPU、内存、IO 等的神秘进程?
【系统DFX】如何诊断占用过多 CPU、内存、IO 等的神秘进程?
106 0
|
3月前
|
存储 JSON 运维
【运维】Powershell 服务器系统管理信息总结(进程、线程、磁盘、内存、网络、CPU、持续运行时间、系统账户、日志事件)
【运维】Powershell 服务器系统管理信息总结(进程、线程、磁盘、内存、网络、CPU、持续运行时间、系统账户、日志事件)
49 0
|
7月前
|
关系型数据库 MySQL PHP
PHP 原生操作 Mysql
PHP 原生操作 Mysql
81 0