1

前段时间遇到一个诡异的问题,连接走 NAT 转发会出现偶尔连接不通的情况,后来检查发现,NATtcp_timestampstcp_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,所以出现了大量的重传。

image

在后端服务器上继续捉包,发现数据包已经到达了后端,但是没有返回 ACK

image

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_timestamptcp_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

参考

  1. Coping with the TCP TIME-WAIT state on busy Linux servers
  2. 一个NAT问题引起的思考
  3. TCP timestamp

程淇铭
4.2k 声望1.7k 粉丝

今晚请吃饭,随便坐