前言:
交易超时,是应用运行中常见的一种异常现象,在问题处置和分析中,也会遇到各种各样的超时,但通讯超时是最为常见的一种报错,本文针对一个第三方支付机构交易超时的案例,谈谈通讯超时的分析经验。
案例描述:
第三方支付机构反馈每天有几百笔交易由于超时而未返回交易结果。该系统的应用访问关系为第三方支付机构->负载均衡设备->应用服务器。在负载均衡设备和服务器上同步抓取网络数据包排查,同时在负载均衡设备上对日志文件执行tail -f ltm|grep "TCP retransmit timeout"进行观察,若有结果反馈,表示正有超时现象发生,则停止抓包,对所捕获的数据包进行分析。
案例分析:
对抓包进行分析
从图中可以发现在时间点19:32:57 LC向F5发送了reset包重置了连接。继续分析该时间段F5和服务器S之间通讯的数据包:
从图中发现F5收到LC发送过来的请求后,即向应用服务器S发送请求,无奈应用服务器未响应TCP三次握手SYN请求。进一步分析服务器上抓取的数据包:发现F5在19:32:53从本地端口18345发起到服务器S目标端口的TCP三次握手SYN请求,但服务器没有响应,F5将请求重发了三次均未得到服务器响应。向前追溯数据流发现,在19:32:47 F5使用了18345和服务器S目标端口成功进行了数据通讯,过了6秒后,F5又使用了18345端口尝试访问服务器S目标端口,此时服务器S的目标端口仍处于TIME_WAIT状态,该状态需持续30s才能释放。
Windows服务器处于TIME_WAIT状态的端口是否均不会响应此前TCP连接的客户端相同端口的请求呢?通过分析服务器的数据包,发现也有可以响应的情况,如下图所示,19:32:31 服务器和F5完成四次握手中断连接,服务器端口处于TIME_WAIT状态,需持续30秒释放,而在19:32:45 F5又通过相同源端口19483访问服务器的目标端口,此时服务器目标端口仍处于TIME_WAIT状态,但此次成功响应了F5的连接请求。服务器响应客户端的SYN并将处于TIME_WAIT状态的端口切换为ESTABLISHED状态,被称为TCP TIME_WAIT Assassination。
服务器何时在接受客户端的的TCP三次握手SYN请求后能将TIME_WAIT状态的端口切换到ESTABLISHED状态?经查询微软官方文档(https://blogs.technet.microsoft.com/networking/2010/08/11/how-tcp-time-wait-assassination-works/),RFC 1122做了如下解答:
即新请求的SYN初始序列号必须大于先前连接的最大序列号,同时不能是先前连接里SYN的重复发送。但同时指出TCP TIME_WAIT Assassination在Windows系统之间能很好地工作,但在Windows和其他操作系统交互时可能不会按预期工作,因F5底层为Linux实现,所以TCP TIME_WAIT Assassination有时会失败,服务器存在无法响应F5的SYN请求的情况。通过分析F5到应用服务器的数据包发现,F5每次将请求发送给应用服务器服务器,服务器响应完请求后,服务器立即发起TCP四次握手拆除连接,如下图所示:
登录服务器检查HTTP KeepAlive均为开启状态,且F5上的Virtual Server已关联了Oneconnect连接复用的配置,正常情况下服务器响应完F5请求后不会立即中断连接,而是保持连接,F5将连接放入连接池中,当下一个请求到来时,直接从连接池中取一个空闲连接来处理访问请求。通过和开发人员沟通,发现应用代码中使用的是HTTP 1.0协议,该协议不支持HTTP KeepAlive功能,处理完请求后即开始TCP四次握手中断连接,造成连接复用无法生效。这种情况下,每当一个新的请求到来时,F5均需要新建到服务器的连接,对F5的端口本地高位端口开销很大,在30秒之内有很大概率重复使用相同端口建立到同一应用服务器端口的连接,进而触发TIME_WAIT Assassination,而TIME_WAIT Assassination在机制上不一定会成功,最终造成向服务器发送请求但无法被响应,导致访问超时。
总结:
后续通过与应用沟通,将代码中的HTTP 1.0均更改为HTTP 1.1,保证F5的连接复用切实生效,极大地降低了F5上本地端口的开销,从而降低了TIME_WAIT Assassination的触发需求,最终保证了请求响应的成功率,未再发生访问超时的现象。
开放系统支持部 胡从兴@ABCDC
领取专属 10元无门槛券
私享最新 技术干货