Content-Length 使用不规范导致 Socket Hang Up 问题
前言
XProxy 是基于 Node.js 研发的七层负载网关,承担着全公司所有互联网和私有云的流量入口,高峰期 QPS 达 20W,日志量每天达数十亿条,部署架构为两地三中心,网关机器集群接近三百台机器。
存在问题
业务方反馈,请求网关接口时出现超时未响应的情况,时而接收到 502 的状态码,错误信息为 Socket Hang Up。
排查过程
在业务方反馈问题后,首先查看网关的运行状态,看到网关的运行是正常的,并且仅仅是一个业务方反馈这个问题,其他业务方使用都是正常的,因此排除是网关应用问题。
接着继续排查网络问题,通过 tcping 发现业务方到网关的网络也是正常的,并且三次握手的时延也是比较低的,因此排除网络问题。
继续查看网关日志,从 Kibana 并没有看到接口正常转发到上游服务的日志,只看到接口的请求日志,并且日志记录了 Socket Hang Up 的 error,因此可以判断网关是接收到了请求,但是没有正常处理请求,那就只能抓包分析,通过抓包可以看到,该请求为 Get 请求,并且神奇的是请求头中竟然存在 Content-Length:
查阅rfc2616,可以清楚的了解到 Content-Length 是记录 body 的大小,一般用于服务端响应客户端时才会带上,作用是告诉客户端读完 Content-Length 字节大小的数据,数据也就传输完了,然而 Get 请求并没有 body,都是表单传输:
从 Github 上也搜索到类似的 issue:
为了更加准确地确定问题,在网关服务器上用相同的请求报文,带上 Content-Length 时问题是必现的,去掉 Content-Length 时就正常了。
带上 Content-Length 的请求:
不带 Content-Length 的请求:
解决方案
将问题反馈给业务方后,建议业务方检测代码使用的 HttpClient 是否正常,了解到当前 HttpClient 使用的是 Rest Templete,业务方确定 RestTemplete 有问题后,将 HttpClient 换成了 OkHttpClient,请求就恢复正常了。
评论