前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SYN和RTO

SYN和RTO

作者头像
LA0WAN9
发布2021-12-14 08:47:19
8360
发布2021-12-14 08:47:19
举报
文章被收录于专栏:火丁笔记

前两天,我在微博上推荐了一篇朝花夕拾的文章:The story of one latency spike,文章中介绍了 cloudflare 工程师如何一步一步 debug 网络延迟问题,细细读来受益良多,不过我并不打算详细介绍那篇文章的细枝末节, 本文只摘录一个点:

When debugging network problems the delays of 1s, 30s are very characteristic. They may indicate packet loss since the SYN packets are usually retransmitted at times 1s, 3s, 7s, 15, 31s.

为什么是 1 秒、3 秒、7 秒、15 秒、31 秒?说来惭愧,我以前从没有注意过 SYN 重建时的时间特征,知耻而后勇,正好借此机会来一探究竟。

下面让我们通过一个实验来重现一下 SYN 超时重传的现象:

  1. 在服务端屏蔽请求:「iptables -A INPUT –dport 1234 –syn -j DROP」
  2. 在服务端监听 1234 端口:「nc -l 1234」
  3. 在客户端开启抓包:「tcpdump -nn -i any port 1234」
  4. 在客户端发起请求:「date; nc <SERVER> 1234; date」

经过一段时间的等待后,我们可以看到 tcpdump 输出如下:

代码语言:javascript
复制
12:53:15.511826 IP CLIENT.53384 > SERVER.1234: Flags [S], ...
12:53:16.511042 IP CLIENT.53384 > SERVER.1234: Flags [S], ...
12:53:18.511058 IP CLIENT.53384 > SERVER.1234: Flags [S], ...
12:53:22.511042 IP CLIENT.53384 > SERVER.1234: Flags [S], ...
12:53:30.511065 IP CLIENT.53384 > SERVER.1234: Flags [S], ...
12:53:46.511068 IP CLIENT.53384 > SERVER.1234: Flags [S], ...

第一行是正常发出的 SYN,后面五行是超时重传发出的 SYN,相对于正常发出的 SYN,它们的延迟分别是:1 秒、3 秒、7 秒、15 秒、31 秒,正好符合开头的描述。之所以重传五次是因为 net.ipv4.tcp_syn_retries 的缺省值是 5。

此外,我们可以看到两次 date 命令输出的时间如下:

代码语言:javascript
复制
Sun Aug 13 12:53:15 CST 2017
Sun Aug 13 12:54:18 CST 2017

可见整个握手过程从开始到超时一共持续了 63 秒,其中 31 秒是总计五次 SYN 发送的时间,剩下的 32 秒是确认第五次 SYN 超时的时间(2 的 5 次方)。由此可见,在握手阶段一旦出现严重丢包,网络延迟会非常久,很多时候这是没有必要的,比如 Web 服务器,可以考虑设置 net.ipv4.tcp_syn_retries 为 2 或者 3 比较合适,一旦出现严重丢包,与其不断重传,不如及时放弃。

如果要研究得更深入些,我们还需要了解 RTO(retransmission timeout),即超时重传时间,具体计算方法很复杂,我就不多说了,有兴趣的可以参考本文解决的推荐链接,你只要知道系统会根据网络连接的情况动态调整该值的大小即可。不过在 SYN 握手阶段,网络连接还没有建立起来,如果此时发生丢包,那么因为系统没有可以参照的 RTT(Round-Trip Time),所以此时只能给出系统缺省设置的 RTO:

代码语言:javascript
复制
#define TCP_RTO_MAX	((unsigned)(120*HZ))
#define TCP_RTO_MIN	((unsigned)(HZ/5))
#define TCP_TIMEOUT_INIT ((unsigned)(1*HZ))

...

unsigned long timeo;

if (req->num_timeout++ == 0)
    atomic_dec(&queue->young);
timeo = min(TCP_TIMEOUT_INIT << req->num_timeout, TCP_RTO_MAX);
mod_timer(&req->rsk_timer, jiffies + timeo);
return;

可见 RTO 的最大值是 120 秒,最小值是 200 毫秒,在连接建立前的初始值是 1 秒,如果经过多次重传,每次 RTO 的值翻倍,但最大不得超过 120 秒:

  1. 第 1 次重传:超时时间是 2 的 0 次方,也就是 1 秒。 延迟:1 秒
  2. 第 2 次重传:超时时间是 2 的 1 次方,也就是 2 秒。 延迟:1 + 2 = 3 秒
  3. 第 3 次重传:超时时间是 2 的 2 次方,也就是 4 秒。 延迟:1+ 2 + 4 = 7 秒
  4. 第 4 次重传:超时时间是 2 的 3 次方,也就是 8 秒。 延迟:1 + 2 + 4 + 8 = 15 秒
  5. 第 5 次重传:超时时间是 2 的 4 次方,也就是 16 秒。 延迟:1 + 2 + 4 + 8 + 16 = 31 秒

说点题外话,很多人在应用层实现失败重试逻辑的时候,往往是单纯的循环重试,这样过于生硬,重试的成功率往往也不高,可以考虑一下 TCP 的翻翻算法。

还有一点需要说明的是,在建立连接后,因为目前网络都很快,所以大部分连接的 RTO 都会接近 TCP_RTO_MIN,也就是 200ms,可以通过「ss -int」命令来确认。关于超时重传还有很多细节需要考虑,下面列出一些资料:

本文相当于快餐,建议仔细阅读如上正餐。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-08-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云服务器
云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档