0x01 故障现像
帮助维护的一台服务器,突然收到报障,说其中一个子域名下的程序最近经常报错,收到之后立刻打开域名检查,发现访问无异常,可以正常显示登录页(此域名需要登录后方可继续访问),看nginx日志,确实有不少502的错误,但大部分是200的
0x02 排查过程
一般出现这样的情况,第一反应就是服务器负载过高导致PHP无法响应,故立即登录服务器查看。发现负载很低(不到1),数据库中也没有大量的请求。由于本地无法复现,故暂时放弃,当它是瞬时的高负载导致(当时半夜了)。
为了方便下次排查,做了一个小脚本,每分钟将数据库的show processlist记录到文件中,方便日后比对。
0x03 问题再次出现
再次收到报障,而此时自己刚好在电脑前,立刻登录服务器,发现负载依然很低(15分钟内的平均负载依然在1以下),查看show processlist的日志文件,并未发现发生故障时数据库高负载。
查看程序中自己写的log,发现没有请求结束的日志,故开始怀疑是否请求并未到达PHP端,查看了php-fpm,发现大量 code 70的日志
通过百度,bing,google,翻查了很久,发现大部分的文章都提示是要修改php-fpm中pm.xxx相关的参数(调整children数之类的)。按照相关文章的做法调整了参数后,发现502依然存在,其出现的时间与php-fpm中code 70的出现时间一致,问题的矛头都指向了php-fpm,但万般搜索都没有结果。
此时再次陷入死胡同。
0x04 再次尝试
因为服务器是用lnmp包安装的,思考方向开始转向是否php版本或是php-fpm一些未知参数配置错误的问题。虽然感觉这个可能性不大(毕竟服务器跑了一年多都没出过故障,也没变更过配置),所以重新编译安装了一个独立的php5.4。安装完成之后单独将此域名的php处理切到此版本去。
然而,问题依然存在。
0x05 转机
再次翻看nginx日志,发现502的页面都集中在登录后的首页(但不是所有请求首页的都报错),故使用管理员账号登录,发现在生产环境上面复现了502错误。激动!此时的思考方向转向了是否为代码上面的问题(此段代码已近一年未修改)。
直接在线上debug(痛苦的过程),发现在一个sql语句查询之后,就会报502的错误。
将查询参数打出来之后,发现入参是一个有3006个int元素的数组(系统跑了一段时间后数据量变大了),在sql要执行in操作。此时问题好像基本确定了。立刻将此语句调整,换了一个方式查询,去掉了in操作。
十分欢喜的将代码上线,然而还是被打击了,502错误依然。
不死心,继续debug。发现出现的地方依然是这个位置。
这时将注意力集中在了一个数据类型处理上
修改中间层函数,增加一个可以控制参数,可以直接返回结果集
至此,问题解决了!
0x06 总结
产生code 70的原因有可能是因为PHP在处理大量数据的时候出现了异常中断,但由于此过程中并没有报memory超限等错误,所以很晚才将问题的方向指向这里。
所以如果再次遇到code 70时,可以尝试通过断点来定位一下是否为代码上的处理问题。