NoHttpResponseException问题分析解决记录
新项目上线遇到NoHttpResponseException的问题
大概11000笔发到C系统的交易会出现15笔会因这种异常而导致失败,对月交易量在近三亿的系统来说,按照这样的比例也会有4万多笔的交易失败,这种严重影响客户体验的现象坚决不能容忍。
按照套路网上搜了下这种出现这种异常的原因以及解决办法,apache网站的解释是:
In some circumstances,usually when under heavy load, the web server may be able to receive requests but unable toprocess them. A lack of sufficient resources like worker threads is a good example. This may cause the server to drop the connection tothe client without giving any response. HttpClient throws NoHttpResponseException when it encounters such a condition. In most cases it is safe to retry a method that failed with NoHttpResponseException.
意思就是当服务器端由于负载过大等情况发生时,可能会导致在收到请求后无法处理(比如没有足够的线程资源),会直接丢弃链接而不进行处理。此时客户端就回报错:NoHttpResponseException。 建议出现这种情况时,可以选择重试。
联系了W公司的同事,确认他们的C系统的负载还远未达到过载的程度,而且我们发到他们B系统的交易从来没有出现过这种异常,他们也无法解释这种异常产生的原因。
抓包看下tcp连接交互的情况
两笔异常交易的共同点就是(以图二为例)C系统在2891个包发来了挥手,然后在2893个包RST了连接,导致我方系统第2888、2889发的请求没有收到响应就异常结束了。
2个问题(自问自推测)
1. C系统为什么会发送结束连接的FIN挥手包?
注意到图二在第2882个包C系统返回前一个请求的响应完成(10:16:25),到第2888个包(10:16:46)我方发送下一个请求,之间有个21s的空闲间隔,图一中C系统在发出FIN挥手包之前也有一个20s的空闲间隔,会不会是C系统的服务器会在每个连接空闲20s后自动就会发起断开连接呢?再看下图三正常结束交易的tcp流,也是在收到客户端的确认包后有20s的空闲间隔。
基本上可以推断出C系统的服务器会在连接空闲20s后自动发起断开连接。
2. C系统为什么会直接发出第2893个RST包,而不是发出正常的Ack确认包?
按照图二的tcp流序列,客户端发出的第2888个包在收到服务端发送的第2891个FIN包之前,只个是在客户端抓的包,请求的网络传输时间。C系统的服务端发出的FIN包时很可能还没收到我方发送的第2888个请求。即服务端发送FIN包后,马上就收到了第2888个请求包,以及第2892个[FIN、Ack]包,自身无法判断是正常结束,所以就发出来RST包,关闭连接。
我方系统是用httpclient4.3的60s的长连接发送请求,使用的http1.1协议连接是默认keepalive的,同一个线程的多个请求可以复用同一个长连接。正是由于c系统发出FIN包的时间,与我方在连接空闲了20s时仍使用这个连接发送数据时之间微妙的时间差,所以导致出异常的交易都满足这样一个现象:即请求发出去才几十毫秒就收到了异常。
解决
基本上明确了异常的原因,那解决办法是?
1. 协调W公司变更配置
前面已经说了我方系统发送到W公司B系统的交易,没有出现过这种异常,说明B系统的服务端在我方长连接存在的60s时间里没有主动发起断开此连接,推测B系统的连接最大空闲时间是大于60s。这个需要抓下与B系统的tcp包就可以分析出B系统有没有主动断开长连接,空闲多少秒断开两个信息。那可不可以协调W公司,请他们将两个系统的连接保持最大空闲时间设置为一致呢?这个只能尽力。
2. 优化我方系统
1)http请求使用重发机制,捕获NohttpResponseException的异常,重新发送请求,重发3次后还是失败才停止。由于不知道客户端捕获到NohttpResponseException这个异常后,客户端是否自动关闭了这个连接,每次重发都需要新建连接发送。新建连接不存在太长的空闲时间问题,因此能够通过重发解决交易失败的问题。
2)我方系统主动检查每个连接的空闲时间,允许设置连接的最大空闲时间M,即客户端建立的连接空闲M秒后,自动发起断开连接。只要这个M时间小于服务端的最大空闲时间,将完全避免服务端主动断开连接导致的异常。
与同事交流,之前鄙司另一个系统到微信支付请求也遇到同样的NohttpResponseException异常,tcp抓包信息如下图:
第47970个包是服务端发来的FIN包,收到响应的ack包立刻就想断开连接(确认是开启keep-alive的,连接保持),而客户端又发送了新的请求包过去,服务端就发送了三条RST包,断开了连接。异常的原因推测是apache网站的解释,对方负载过大主动断开连接,也按照网站推荐的做法,捕获异常重发,后面就没有再遇到因这种异常而引起交易失败。
以上就是NoHttpResponseException问题分析解决记录的详细内容,更多关于NoHttpResponseException问题解决的资料请关注脚本之家其它相关文章!
最新评论