前段时间遇到一个诡异的问题,连接走 NAT
转发会出现偶尔连接不通的情况,后来检查发现,NAT
加 tcp_timestamps
和 tcp_tw_recycle
会造成后端服务器丢包。
1 问题现象
有几个内网服务器,需要通过特定外网服务器做 NAT
去访问,这个 NAT
做的是 FULL NAT
,不仅替换了连接的 dst ip
,还替换了连接的 src ip
。然后发现 telnet
同一个 NAT
服务器的 IP 端口时,部分服务器能够连接,部分卡在那里,最后报一个连接超时的错误
telnet: connect to address xxx.xxx.xxx.xxx: Connection timed out
2 定位原因
在测试服务器上模拟现象
- 10.0.1.24: 连接端
- 192.168.41.34:
NAT
所在机器 - 192.168.41.31: 后端服务器所在机器
测试的时候触发连接不通的现象,在 NAT
服务器上使用 tcpdump
捉包,在 Wireshark
上查,发现从 Client
出来的握手包都已经转发到 Server
端,但是后端服务器没有回复 ACK
,所以出现了大量的重传。
在后端服务器上继续捉包,发现数据包已经到达了后端,但是没有返回 ACK
以 NAT后端丢包
为关键词搜索相关信息,发现 NAT 模式建议关闭 tcp_tw_recycle
,于是手动关闭 time-wait 复用
sysctl net.ipv4.tcp_tw_recycle=0
连接不通的问题再也没有出现,问题解决
3 问题分析
3.1 tcp_tw_recycle
开启 tcp_tw_recycle
即允许复用 TIME-WAIT
状态的 TCP 连接,在做 TCP 优化时往往会启用这个选项。
3.2 NAT
NAT的全称是:Network Address Translation(网络地址转换),会在转发过程中替换TCP包的源地址或目的地址,分为称 SNAT 和 DNAT。
比如说,A
要通过 NAT
服务器 B
的 80 端口 去访问 C
的 80 端口,A 发出的包是 (A,XX,B,80)
经过 DNAT
转换后变为 (A,XX,C,80)
,再经过 SNAT
转换后变为 (B,XX,C,80)
,于是 C
看到的是来自于 B:XX
的连接。
3.3 Per-host PAWS机制
同时开启 tcp_timestamp
和 tcp_tw_recycle
会启用TCP/IP协议栈的 per-host 的 PAWS 机制,这种机制要求所有来个同一个 host IP 的TCP数据包的
timestamp 值是递增的。当收到一个 timestamp 值,小于服务端记录的对应值后,则会认为这是一个过期的数据包,然后会将其丢弃。
3.4 丢包原因
经过同一个 NAT 转换的数据包在 Server 端看来是和同一个 Client 打交道,虽然经过 NAT
转换,但是不同 Client 所携带的 timestamp
是不一样的,无法保证整过 NAT 转化后的数据包携带的 timestamp
值严格递增,所以会出现丢包。
4 最后解决方案
在使用 NAT 做转发或者做负载均衡的时候,关闭后端服务器的 tcp_tw_recycle
功能,保留 tcp_timestamps
。
参考
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。