Linxu在NAT或SLB负载环境配置内核tcp_tw_recycle参数导致SYN重传

Tcp_tw_recle_syn_repeat

Posted by BlueFat on Thursday, May 24, 2018

公司的网络环境下打开App加载奇慢或者无响应,各路排查是当时优化了内核net.ipv4.tcp_tw_recycle快速回收time_wait参数导致。

Server端可以快速回收处于TIME_WAIT状态的socket

cat /proc/sys/net/ipv4/tcp_tw_recycle
1
cat /proc/sys/net/ipv4/tcp_timestamps
1

tcp_tw_recycle 的坑

解释一下,TCP 主动关闭连接的一方在发送最后一个 ACK 会进入 TIME_AWAIT 状态,再等待 2 个 MSL 时间后才会关闭(因为如果 server 没收到 client 第四次挥手确认报文,server 会重发第三次挥手 FIN 报文,所以 client 需要停留 2 MSL的时长来处理可能会重复收到的报文段;同时等待 2 MSL 也可以让由于网络不通畅产生的滞留报文失效,避免新建立的连接收到之前旧连接的报文),了解更详细的过程请参考 TCP 四次挥手。

参数 tcp_tw_recycle 用于快速回收 TIME_AWAIT 连接,通常在增加连接并发能力的场景会开启,比如发起大量短连接,快速回收可避免 tw_buckets 资源耗尽导致无法建立新连接 (time wait bucket table overflow)

查得 tcp_tw_recycle 有个坑,在 RFC1323 有段描述:

An additional mechanism could be added to the TCP, a per-host cache of the last timestamp received from any connection. This value could then be used in the PAWS mechanism to reject old duplicate segments from earlier incarnations of the connection, if the timestamp clock can be guaranteed to have ticked at least once since the old connection was open. This would require that the TIME-WAIT delay plus the RTT together must be at least one tick of the sender’s timestamp clock. Such an extension is not part of the proposal of this RFC.

大概意思是说 TCP 有一种行为,可以缓存每个连接最新的时间戳,后续请求中如果时间戳小于缓存的时间戳,即视为无效,相应的数据包会被丢弃。

Linux 是否启用这种行为取决于 tcp_timestamps 和 tcp_tw_recycle,因为 tcp_timestamps 缺省开启,所以当 tcp_tw_recycle 被开启后,实际上这种行为就被激活了,当客户端或服务端以 NAT 方式构建的时候就可能出现问题。

当多个客户端通过 NAT 方式联网并与服务端交互时,服务端看到的是同一个 IP,也就是说对服务端而言这些客户端实际上等同于一个,可惜由于这些客户端的时间戳可能存在差异,于是乎从服务端的视角看,便可能出现时间戳错乱的现象,进而直接导致时间戳小的数据包被丢弃。如果发生了此类问题,具体的表现通常是是客户端明明发送的 SYN,但服务端就是不响应 ACK。

但对于NAT环境不适用,会导到NAT设备后面的Client连接Server不稳定。

在高并发的 WebServer上,为了端口能够快速回收,打开了 tcp_tw_recycle , 关闭 tcp_tw_reccycle 的时候,内核是不会检查对端机器的包的时间戳的; 打开 tcp_tw_recycle 了,就会检查时间戳,若发包的时间戳是乱跳的,则内核会当带了“倒退”的时间戳的包当作是“recycle的tw连接的重传数据,不是新的请求”,于是丢掉不回包,造成大量丢包。

解决

在/etc/sysctl.conf配置文件添加如下内容。

net.ipv4.tcp_tw_recycle=0
net.ipv4.tcp_timestamps=0

执行如下命令,使配置生效。

sysctl -p

抓包分析

第一步抓取了代理客户端发出去的包,通过tcpdump -i en0 -nn host xxxx 只抓访问服务器的包。

看到Retransmission重传 在网络环境中,数据包丢失是非常常见的事情。TCP协议有内建的处理机制来确保网络数据传输正确。但是,如果看到大量的TCP重传(TCP Retransmission),则往往表示存在异常。

当数据发送方没有接收到接收方的ACK,就会TCP Retransmission。

1.通过抓包结果来看。错误的包基本定位在SYN一直重传,而服务器端没有SYN+ACK。回想三次握手流程。

a.经过排查在服务器没有SYN+ACK期间,是有其他连接的在传输数据的。

b.既然网络正常连接,而一直SYN重传,说明服务器一直没有收到SYN包或者没有正确处理SYN包,如果服务器收到SYN包后,发送SYN+ACK,而没有收到客户端的ACK,那么服务器也会一直重传ACK+SYN,显然没有。

关于为什么服务器为什么没有响应。通过netstat -natp |grep  SYN_RECV,服务器压根没有理会这个包。猜测是内核参数问题。 经过排查是当时优化了内核net.ipv4.tcp_tw_recycle快速回收time_wait参数导致。

tcp_tw_recle参数引发的SYN重传
Linux系统内核配置问题导致NAT环境访问实例出现异常