网站每天有大约1亿的流量(请求数),目前只有几台机器,压力比较大。

最近,网站访问的时候经常出现502 Bad Gateway的错误提示,有几个同事处理了几个星期没有找到问题的原因,昨天史哥让我看看日志,看看能不能找出点头绪。

虽然是nginx反向代理报的错,但很明显是后面的php服务器出了问题了,一般就是请求超时,之前用php取数据的数据的时候没有设置超时时间,结果导致请求时间过长,fast cgi进程数增加,大部分的php-cgi的资源都在等待外部接口返回数据,导致新的请求得不到处理。解决方案就是所有的取数据的工作要么:1)做成crontab的形式去取,2)在php代码里面去的时候,一定要设置超时时间。

一般的PHP网站的架构差不多类似于下图:

image

整个系统并发数的瓶颈在php-cgi上,一般也是200r/s,但是由于程序或者其他原因导致处理请求的时间过长的话(如:3s-5s),则php-cgi处理的能力就会下降3-5倍,新的请求无法得到处理,超时也是难免了。

那么,当遇到类似的问题时,应该如何排查呢?

个人觉着,可以从nginx的error log查起。虽然是提供web服务的php端出的问题,但是web日志对问题的记录却没有帮助,因为处理请求的时间长对于web服务器来说并不是错误。nginx反向代理则会记下所有请求超时的链接,会对问题的排查帮助很大。

假设当1秒钟同时过来200个请求的时候,可能有50个请求是有问题的,这50个请求会占用5秒的时间处理,当第2秒的200个请求过来的时候,有50个还没处理完,所以有50个请求会得不到资源来处理,以此类推,当第4秒的时候,就可能会有大部分的资源都用在超时的请求上了,502也就在所难免了。

nginx的error log的大部分的超时请求应该是有问题的请求(本身就超时的请求),也附带有一部分的正常请求(因得不到资源而超时的请求),在分析排查原因的时候,不要被第二种情况干扰了,对这些请求的链接做一下归并,找出数目最多的来,差不多就是有问题的请求。

本次线上的问题是由于输入参数为空导致数据库查询返回条目过多,消耗了大量的资源导致的。在程序上加上空参数验证即可解决问题。

出问题的同事被史哥“责令”买水给大伙喝。