问题:为什么你的 SYN 包被丢了——求答案

问题:为什么你的 SYN 包被丢了——求答案

江湖有个传说:一旦设置了 net.ipv4.tcp_tw_recycle 在 NAT 场景下(多个客户端经过一个 LVS 访问一个服务端,NAT 后服务端看到的客户端是同一个 IP) 就会发生丢包

也可以看看这节:https://xiaolincoding.com/network/3_tcp/syn_drop.html#%E5%9D%91%E7%88%B9%E7%9A%84-tcp-tw-recycle

我们来重现和分析一下这个问题,这应该会是个连续剧,我会根据大家实验情况来推进后面的内容

客户端

我们默认 99 的 ECS 就行,默认配置。

1
yum install tcptraceroute //装一下这个工具,可以对端口进行探测

想要持续对端口探测,类似 ping 一样,就装一下下面的 shell 脚本(tcpping , tcpping 里面会调用 tcptraceroute ):

介绍:http://www.vdberg.org/~richard/tcpping.html

脚本我放仓库里了:https://github.com/plantegg/programmer_case/commit/7c59a7d3666db2fe5af9ba598104cd88cad52497

探测端口通不通:

1
tcpping -d 1.2.3.4 22

通的话会收到:

1
seq 0: tcp response from e237  <syn,ack>  0.088 ms

端口不存在肯定不通,且会被 RST

1
seq 3: tcp response from e237  <rst,ack>  0.076 ms

端口在但是偶尔不通,是今天的主角:

1
2
3
4
5
6
Thu Aug  8 16:48:44 CST 2024
traceroute to , 255 hops max, 60 byte packets
seq 13: tcp response from <syn,ack> 28.850 ms //通
Thu Aug 8 16:48:52 CST 2024
traceroute to , 255 hops max, 60 byte packets
seq 21: no response (timeout) //不通

服务端

建议找一个 3.10 内核的机器,4.13 开始已经没有 tcp_tw_recycle 这个参数了

1
2
3
4
5
6
#sysctl -a |egrep "recycle|timestamp"
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_tw_recycle = 1 //这个参数默认是 0,必须改成 1

#uname -r
3.10.0-1062.18.1.el7.x86_64 //我在阿里云上买的一个 CentOS7,版本只要是 4.12 之前的都行

实验步骤

  1. 服务端随便起一个 http 服务端口,比如 1234
  2. 在客户端上执行 tcpping -d 服务端 ip 1234 //这一步可以看到 100% 是通的
  3. 在客户端执行下 curl 服务端 ip:1234 //可以很快看到 tcpping 开始报偶尔通/偶尔不通

重现效果,如下图,本来一次都没有 timeout,但我 curl 一下立即就 timeout 了

img

请分析,为什么 curl 一下 tcpping 就不通了?