【每日一记11】+第7天:彻底弄懂TCP协议:从三次握手说起(七)
  

易逝的信仰 411

{{ttag.title}}

疑症(8)TCP 的重传机制以及重传的超时计算


【1】TCP 的重传超时计算


TCP 交互过程中,如果发送的包一直没收到 ACK 确认,是要一直等下去吗?显然不能一直等(如果发送的包在路由过程中丢失了,对端都没收到又如何给你发送确认呢?),这样协议将不可用,既然不能一直等下去,那么该等多久呢?等太长时间的话,数据包都丢了很久了才重发,没有效率,性能差;等太短时间的话,可能 ACK 还在路上快到了,这时候却重传了,造成浪费,同时过多的重传会造成网络拥塞,进一步加剧数据的丢失。也是,我们不能去猜测一个重传超时时间,应该是通过一个算法去计算,并且这个超时时间应该是随着网络的状况在变化的。为了使我们的重传机制更高效,如果我们能够比较准确知道在当前网络状况下,一个数据包从发出去到回来的时间 RTT——Round Trip Time,那么根据这个 RTT 我们就可以方便设置 TimeOut——RTO(Retransmission TimeOut)了。


为了计算这个 RTO,RFC793 中定义了一个经典算法,算法如下:


[1] 首先采样计算RTT值


[2] 然后计算平滑的RTT,称为Smoothed Round Trip Time (SRTT),SRTT = ( ALPHA * SRTT ) + ((1-ALPHA) * RTT)


[3] RTO = min[UBOUND,max[LBOUND,(BETA*SRTT)]]


其中:UBOUND 是 RTO 值的上限;例如:可以定义为 1 分钟,LBOUND 是 RTO 值的下限,例如,可以定义为 1 秒;ALPHA is a smoothing factor (e.g., .8 to .9), and BETA is a delay variance factor(e.g., 1.3 to 2.0).


然而这个算法有个缺点就是:在算 RTT 样本的时候,是用第一次发数据的时间和 ack 回来的时间做 RTT 样本值,还是用重传的时间和 ACK 回来的时间做 RTT 样本值?不管是怎么选择,总会造成会要么把 RTT 算过长了,要么把 RTT 算过短了。如下图:(a)就计算过长了,而(b)就是计算过短了。



针对上面经典算法的缺陷,于是提出 Karn / Partridge Algorithm 对经典算法进行了改进(算法大特点是——忽略重传,不把重传的 RTT 做采样),但是这个算法有问题:如果在某一时间,网络闪动,突然变慢了,产生了比较大的延时,这个延时导致要重转所有的包(因为之前的 RTO 很小),于是,因为重转的不算,所以,RTO 就不会被更新,这是一个灾难。于是,为解决上面两个算法的问题,又有人推出来了一个新的算法,这个算法叫 Jacobson / Karels Algorithm(参看 FC6289),这个算法的核心是:除了考虑每两次测量值的偏差之外,其变化率也应该考虑在内,如果变化率过大,则通过以变化率为自变量的函数为主计算 RTT(如果陡然增大,则取值为比较大的正数,如果陡然减小,则取值为比较小的负数,然后和平均值加权求和),反之如果变化率很小,则取测量平均值。


公式如下:(其中的 DevRTT 是 Deviation RTT 的意思)


SRTT = SRTT + α (RTT – SRTT)  —— 计算平滑RTT


DevRTT = (1-β)*DevRTT + β*(|RTT-SRTT|) ——计算平滑RTT和真实的差距(加权移动平均)


RTO= µ * SRTT + ∂ *DevRTT —— 神一样的公式


(其中:在Linux下,α = 0.125,β = 0.25, μ = 1,∂ = 4 ——这就是算法中的“调得一手好参数”,nobody knows why, it just works…) 最后的这个算法在被用在今天的TCP协议中并工作非常好


最后的这个算法在被用在今天的 TCP 协议中并工作非常好。


知道超时怎么计算后,很自然就想到定时器的设计问题。一个简单直观的方案就是为 TCP 中的每一个数据包维护一个定时器,在这个定时器到期前没收到确认,则进行重传。这种设计理论上是很合理的,但是实现上,这种方案将会有非常多的定时器,会带来巨大内存开销和调度开销。既然不能每个包一个定时器,那么多少个包一个定时器才好呢,这个似乎比较难确定。可以换个思路,不要以包量来确定定时器,以连接来确定定时器会不会比较合理呢?目前,采取每一个 TCP 连接单一超时定时器的设计则成了一个默认的选择,并且 RFC2988 给出了每连接单一定时器的设计建议算法规则:


[1].每一次一个包含数据的包被发送(包括重发),如果还没开启重传定时器,则开启它,使得它在 RTO 秒之后超时(按照当前的 RTO 值)。[2]. 当接收到一个 ACK 确认一个新的数据;如果所有的发出数据都被确认了,关闭重传定时器;[3].当接收到一个 ACK 确认一个新的数据,还有数据在传输,也就是还有没被确认的数据,重新启动重传定时器,使得它在 RTO 秒之后超时(按照当前的 RTO 值)。


当重传定时器超时后,依次做下列 3 件事情:[4.1]. 重传最早的尚未被 TCP 接收方 ACK 的数据包;[4.2]. 重新设置 RTO 为 RTO *2(“还原定时器”),但是新 RTO 不应该超过 RTO 的上限(RTO 有个上限值,这个上限值最少为 60s);[4.3]. 重启重传定时器。


上面的建议算法体现了一个原则:没被确认的包必须可以超时,并且超时的时间不能太长,同时也不要过早重传。规则[1][3][4.3]共同说明了只要还有数据包没被确认,那么定时器一定会是开启着的(这样满足没被确认的包必须可以超时的原则)。规则[4.2]说明定时器的超时值是有上限的(满足超时的时间不能太长)。


规则[3]说明,在一个 ACK 到来后重置定时器可以保护后发的数据不被过早重传;因为一个 ACK 到来了,说明后续的 ACK 很可能会依次到来,也就是说丢失的可能性并不大。规则[4.2]也是在一定程度上避免过早重传,因为,在出现定时器超时后,有可能是网络出现拥塞了,这个时候应该延长定时器,避免出现大量的重传进一步加剧网络的拥塞。

打赏鼓励作者,期待更多好文!

打赏
2人已打赏

gqce 发表于 2020-9-10 10:11
  
感谢分享
伊利丹·怒风 发表于 2021-6-27 23:06
  
多谢楼主的分享,期待你的更多技术贴
伊利丹·怒风 发表于 2021-6-27 23:07
  
多谢楼主的分享,期待你的更多技术贴
发表新帖
热门标签
全部标签>
每日一问
每周精选
技术笔记
技术盲盒
2024年技术争霸赛
产品连连看
干货满满
2023技术争霸赛专题
技术咨询
标准化排查
技术晨报
新版本体验
通用技术
自助服务平台操作指引
秒懂零信任
文档捉虫活动
信服课堂视频
GIF动图学习
答题自测
功能体验
每日一记
SDP百科
技术圆桌
在线直播
安装部署配置
测试报告
畅聊IT
专家问答
MVP
网络基础知识
升级
安全攻防
上网策略
日志审计
问题分析处理
流量管理
运维工具
云计算知识
用户认证
原创分享
解决方案
sangfor周刊
VPN 对接
项目案例
SANGFOR资讯
专家分享
技术顾问
信服故事
功能咨询
终端接入
授权
设备维护
资源访问
地址转换
虚拟机
存储
迁移
加速技术
排障笔记本
产品预警公告
玩转零信任
信服圈儿
S豆商城资讯
技术争霸赛
「智能机器人」
追光者计划
深信服技术支持平台
社区帮助指南
答题榜单公布
纪元平台
卧龙计划
华北区拉练
天逸直播
以战代练
山东区技术晨报
齐鲁TV
华北区交付直播
北京区每日一练

本版版主

461
245
13

发帖

粉丝

关注

本版达人

feeling

本周分享达人

新手29676...

本周提问达人