【故障描述】
近期有同学在使用一个内部应用系统时,偶尔会出现页面报错的情况,Ajax报503错误。
【错误现象】
在页面上操作并提交之后,过一段时间(通常不超过1分钟)之后Ajax会返回503错误码,无法正常使用。在其它同学机器上反复测试,错误一直无法重现。
【错误定位】
503在HTTP状态码中表示Service Unavailable,首先怀疑是服务端繁忙或逻辑异常。排查了后端Resin的执行日志,并未发现异常信息。
一开始怀疑是浏览器版本导致的不兼容问题,后升级为和出错同学相同的浏览器版本后反复测试依然无法重现错误,可以排除浏览器问题。
不考虑代理及LB负载均衡,用户操作流程如下:
1、 用户通过浏览器请求jsp请求,然后等待服务器返回数据(或者超时)。
2、 Resin调用外部接口请求数据。
3、 Resin等待外部接口返回数据。
4、 Resin返回数据给浏览器。
针对一次出现503错误的用户会话,通过检查日志文件发现Resin及外部接口均未出现异常,并且服务器负载较低不会出现拒绝服务的情况。
检查LB访问日志,出现503错误的访问请求在LB上返回码是200。
这说明访问请求经过LB时也是成功的。基本可以排除后端Resin及外部接口的问题,故障出在浏览器和LB之间。
现在再来看出错时返回的Response信息:
Cache-Control no-cache
Connection Close
Info recv 0 bytes from server
Server minnow-jspserver
TARGET-SERVER-IP 127.0.0.1:80
从上面响应头信息看, 连接被关闭,目标IP为127.0.0.1,这是一台内网代理服务器。
于是怀疑是否由于代理服务器繁忙导致部分连接被关闭,修改本地浏览器代理为上面IP地址,经过多次测试依然无法重现错误。
于是想办法导出最近一天的代理服务器访问日志,结果出乎意料,发生错误时用户请求在代理服务器上的返回码也是200,即代理服务器并未过载或异常。
到这里为止,基本可以确定问题出在用户浏览器到代理之间的网络上。
在出错同学机器上执行同样命令,Route输出相同但响应速度却变得非常慢。显然在出现错误的机器上,网络状况是异于寻常的。
这时候注意到发生503错误时,返回的Response信息包含了一个名为minnow-jspserver的字段,咨询同事得知这是一个浏览器CGI插件,启用该插件后浏览器的所有访问都会通过该插件进行转发。
和相关同事确认,出现503错误的机器上全部都安装了该插件。于是判断故障由该插件引起,接下来进行测试验证。
下载并安装minnow 插件,通过页面测试结果如下:
1、 启用插件,检查过程报503错误。
2、 停用插件并结束对应进程后重试,错误消失。
3、 再次启用插件后重试,再次出现503报错。
至此,可以确认该故障由minnow插件引起,但触发报错的原因是什么呢?
在本地使用TCP抓包,从抓包结果可以看出,安装Minnow插件之后,当请求超过一定时间(测试时为18秒),会出现客户端连接断开的请况。
当连接断开时,Ajax因为连接被关闭抛出503异常。
【解决方案】
在该插件BUG修复之前,可以临时采用以下解决方案:
1、在页面逻辑修复之前,可以先停用该插件及对应服务。
2、修改页面处理逻辑,使用异步或HTTP短连接定时拉取的方式规避该问题。
【结论】
因为网络及运营环境的复杂性,当服务出现访问异常时,真正的原因可能不是非常直观的暴露在我们面前。这时候就需要从多方面分析用户的出错场景,层层排查直到找到问题的真正原因。