TIME_WAIT状态下连接复用导致的问题

现象

生产环境,某个片区应用对接的一个后台服务出现大批量延迟。

背景

应用与后台服务之间经过F5负载均衡器, 通过HTTP方式通信。我们知道TCP在断开连接的时候,会有四次通信,发起方在最后会有2MSL的等待时间,进入TIME_WAIT状态。TIME_WAIT状态存在理由:
1)可靠的实现TCP全双工连接的终止。在进行关闭连接四次挥手协议时,最后的ACK是由主动关闭端发出的。如果这个最终的ACK丢失,另一方将重发最终的FIN。因此主动发起方必须维护状态信息允许它自身重发最终的ACK。假如不维持这个状态信息,那么发起方将响应RST分节,另一方将此分节解释成一个错误(java中将会抛出connection reset的SocketException)。
因此,要实现TCP全双工连接的正常终止,必须处理终止序列四个分节中任何一个分节的丢失情况,主动关闭的一方必须维持状态信息进入TIME_WAIT状态。
2)允许老的重复分节在网络中消逝。TCP分节可能由于路由器异常而”迷途”,在迷途期间,TCP发送端可能因确认超时而重发这个分节,迷途的分节在路由器修复后也会被送到最终目的地,这个原来的迷途分节就称为lost duplicate。
在关闭这个TCP连接后,马上又重新建立起一个相同IP地址和端口之间的TCP链接,后一个连接 被称为前一个连接的化身(incarnation),那么有可能出现这种情况,前一个连接的迷途重复分组在前一个连接终止后出现,从而被误解成从属于新的化身。
为了避免这个情况,TCP不允许处于TIME_WAIT状态的连接启动一个新的化身,因为TIME_WAIT状态持续2MSL,就可以保证当成功建立一个TCP连接时候,来自连接先前化身的重复分组已经在网络中消逝。
TIME_WAIT状态下连接复用:

net.ipv4.tcp_tw_reuse=1,

也就是说一个TIME_WAIT状态的四元组(即一个socket连接)可以重新被新到来的SYN连接使用,需要满足以下两点的其中之一:

1.初始序列号比TIME_WAIT老连接的末序列号大。
2.如果使用了时间戳,那么新到来的连接的时间戳比旧连接的时间戳大。

原因

1、F5负载均衡器与后端服务通信的时候,未设置IP透传,采用F5本身IP与后端服务通信。
2、前台应用在采用HTTP通信的时候,修改了keepalive,将默认的长连接改成了短连接。
3、导致F5与后端服务通信的时候,经常进入TIME_WAIT状态,而后台服务设置了连接复用。
4、由于前台应用集群部署,不同机器请求到达F5的时间戳不一致,而F5透传时间戳,未进行修改。

解决

F5负载均衡器修改每次请求的时间戳,按递增顺序设置,满足后台服务连接复用。