1. 启用日志记录并计划后续故障排除。
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慢,格式如下(详细可以查看之前发布的PHP慢日志的分析)
[日期时间][poolwww]pid进程号
script_filename=脚本文件
[0x00007f2d286c2790]替换()/xxx/Plugin.php:72
[0xx0000700007fff78ab0000ff0]替换()未知:0
[0x00007f2d286c2420]call_user_func_array()/xxx/Plugin.php:489
[0xx0000700007fff78ab0430]__call()未知:0
[0x00007f2d286c1f78]contentEx()/xxx/Abstract/Contents.php:141
[0x00007f2d286c1b78]___content()/xxx/Widget.php:385
[0x00007f2d286c10f8]+++转储失败
1.3 使用ll /proc/进程号/fd/查看PHP进程当前正在操作哪些文件。
使用 strace -o/tmp/output.txt-T-tt-F-etrace=all-p 来跟踪进程(参见我之前发布的 strace 命令的使用)
[root@localhostwww]#cat/tmp/output.txt
6190518:00:40.169437epoll_wait(8,{},1,409)=0
6190518:00:40.579997getsockopt(7,SOL_TCP,TCP_INFO,“n@B17302 200″…,[104])=0
6190518:00:40.580786epoll_wait(8,{},1,1000)=0
6190518:00:41.583271getsockopt(7,SOL_TCP,TCP_INFO,“n@B17302 200″…,[104])=0
6190518:00:41.585020epoll_wait(8,{},1,999)=0
6190518:00:42.587037getsockopt(7,SOL_TCP,TCP_INFO,“n@B17302 200″…,[104])=0
二、结合以上日志分析可能出现的问题
2.1 php错误日志中存在大量一般性错误,例如mysql使用事务导致死锁
2.2 php慢查询日志可以知道这些函数比较耗时,可以考虑使用扩展来解决耗时问题,也可能是file_get_contents等大量默认不超时的函数代码中使用的
*file_get_contents 一步完成打开、读取、关闭三个动作。 过程相当手动,而且可以读取远程内容php慢,非常方便。 在网络条件较差的情况下,可能会导致程序执行停滞。 或太慢,
由于不断重试,等待PHP进程本身超时就会退出。具体可以参考我发布的file_get_contents(扩展函数)内部实现分析。
*这个问题通过跟踪PHP-FPM进程也可以知道,是否有大量的epoll或select超时
2.3 查询TCP连接是否存在大量TIME_WAIT,并查询具体原因(可以参考我之前发表的关于TCP以及异常情况下HTTPKeep-Alive推送TIME_WAIT的影响)。 HTTP合约版本1.1规定默认行为是Keep-Alive,
即TCP连接会被复用来传输多个请求/响应,并且从nginx到php-fpm的原始地址是相同的,TCP连接会受到限制。 由于频繁的TCP连接建立和关闭,会离开TIME_WAIT状态,
一旦端口进入服务器的TIME_WAIT黑名单,也会造成相当大的超时等待,甚至阻塞等待
* 可以详细查看TIME_WAIT对http的影响。
三、解决问题
*php对于人类来说是一个伟大的东西,但是并不意味着他永远不会有bug。 如果想了解更多可以去bugs.php.net查看
3.1 根据正则日志,分析是否存在恶意请求,比如超大表达式的哈希攻击,我们可以看到是一个哈希表,包含$_POST、$_GET,而且哈希表看起来是一个Linked列表,每个元素都是一个数组,
当存在恶意帖子时,帖子中大量的a[]=1&a[]=1&a[]=1&a[]=1&...数组会导致哈希冲突,形成超大数组,造成严重的后果效率下降
* 详细内容请参考我之前关于PHP哈希表碰撞攻击的文章
3.2 php-5的PHP解析multipart/form-datahttp请求的bodypart请求头时,重复复制字符串,导致DOS。 远程攻击者发送恶意构造的multipart/form-data请求,导致服务器CPU资源耗尽,从而远程DOS攻击服务器。
*这个bug比较新,是去年年中的bug,恐怕还有大量的服务器没有安装补丁(可以参考我之前发布的PHP5的严重bug,虽然这是没有换行造成的悲剧)
3.3 如果你关注PHP的开发,你会知道很多这种类型,没有人是完美的,根据具体的日志和问题,你也许能够发现并向PHP提出新的bug
四、系统优化
4.1 并不是说打开的进程越多越好; 拿着16核CPU,运行100多个PHP-FPM进程+100多个nginx进程,纯粹是爽; 进程切换时CPU不努力工作吗?
4.2 代码和系统的优化是否已经达到最佳状态; 可以考虑使用xcache或者apc来优化opcode,这样就不用每次都去解析PHP脚本,直接缓存中间代码,可以提升几十倍的性能