[2024][Protocol] TCP 超时重传时间的计算

因为网络类型的多样性和复杂性,以及中间系统使用TCP协议的范围不同,重传超时时间(Retransmission Timeout,RTO)必须动态地计算。

RFC 1122: Requirements for Internet Hosts 规定允许重传的包和原来的包一模一样 (数据边界,任何头部信息均未改变),因此,可能使用相同的IPv4标识字段(Identification Field)。

任何TCP实现均不能依赖该字段进行交互,因为该字段既不标识重复发送的TCP报文,也不用于标识重复接收的TCP报文。

1.1 重传算法

本部分内容基于 RFC 6298: Computing TCP’s Retransmission Timer 以及 TCP协议中的RTO计算方式分析 - Nut’s Blog

TCP使用 重传计时器 (Retransmission Timer) 来确保对未收到相应确认的数据的传输。该时间称为RTO(Retransmission TimeOut)

1.1.1 基本算法

为了计算当前的RTO,TCP发送端需要维护两个状态变量(State Variables):SRTT (Smoothed round-trip time) & RTTVAR (Round-Trip Time Variation,往返时间差异)

调整SRTT,RTTVAR,RTO 的规则如下:

F ( R T T ) − > R T O F(RTT)->RTO F(RTT)>RTO , F ( ) F() F() 逻辑如下,我们假设, F ( ) F() F()会将一些关于当前连接的变量保存在RAM中。

  • 当RTT的值在 发送端-接收端 之间的报文传输时被确定,发送端应该将RTO设置为 1 秒。注意,RFC 6298 文档之前的版本规定RTO应该被初始化为3秒;一些TCP实现可能仍然使用这个值,或者其他大于1的值。至于为什么将RTO设置的更小,一会说(1.1.6)

  • 首个 (First)RTT的值 R 产生时,主机(Host)必须调整以下的内容

    S R T T = R SRTT=R SRTT=R

    R T T V A R = R / 2 RTTVAR=R/2 RTTVAR=R/2

    R T O = S R T T + m a x ( G , K × R T T V A R )    w h e r e   K = 4 , G   i s   c l o c k   g r a n u l a r i t y   i n   s e c o n d s RTO=SRTT+max(G,K\times RTTVAR)\space \space where\space K=4 ,G\space is\space clock\space granularity\space in\space seconds RTO=SRTT+max(G,K×RTTVAR)  where K=4G is clock granularity in seconds

关于G:G是一个常量,我们必须保证RTO的方差至少为G。后面还会提到1.1.3

  • 若不是首个 RTT 值,则

    $RTTVAR=(1-\beta)\times RTTVAR+\beta\times |SRTT-R’| $

    S R T T = ( 1 − β ) × S R T T + α × R ′ SRTT = (1-\beta)\times SRTT+\alpha\times R' SRTT=(1β)×SRTT+α×R

    其中, R T T V A R RTTVAR RTTVAR 计算所使用的左值 S R T T SRTT SRTT S R T T SRTT SRTT​ 更新之前的值,即上述两个公式实现时必须确保其计算顺序。Congestion Avoidance and Control 建议参数为 α = 1 / 8 ,   β = 1 / 4 \alpha=1/8,\space \beta=1/4 α=1/8, β=1/4

    在经过上述计算后,更新RTO: R T O = S R T T + m a x ( G , K × R T T V A R ) RTO=SRTT+max(G,K\times RTTVAR) RTO=SRTT+max(G,K×RTTVAR)

SRTT 与 RTTVAR 的计算是移动平均值算法。这样的方式也使得越久远的数据对当前结果影响越小,越近的数据对当前结果影响越大,既避免了网络状况抖动对估算结果的影响,又使得该数据尽可能反应当前网络状况

/* Given a new RTT measurement `RTT' */
if (/*RTT is the first measurement made on this connection*/) {
	SRTT    := RTT
	RTTVAR  := RTT / 2
	RTO	:= SRTT + max(G, 2 * RTT)	/* G is clock granularity in seconds */
    //  RTTVAR = RTT/2 , 4*RTTVAR = 2*RTT 
} else {
    
	SRTT'	:= SRTT  +  1/8 * (RTT - SRTT)
	RTTVAR' := 3/4 * RTTVAR  +  1/4 * |RTT - SRTT|
     
	RTO	:= SRTT' + max(G, 4 * RTTVAR')	
}
  • 无论何时,都应该确保RTO至少为1秒,如果真实计算的RTO小于1秒,则取上整为1秒。TCP实现使用 coarse-grained clocks (粗粒度时钟) 进行RTT测量,这导致RTO的最小值往往非常大,研究建议,应该让RTO的最小值大一点,这会使得TCP尽可能保守(conservative),并避免不必要的重传。因此,将RTO的最小值给大一点是一个比较保守的做法。也许未来的研究可能发现使用更小一点的值也是可接受的,甚至得到更优的性能。
  • RTO 的最大值可以是至少 60 秒
1.1.2 RTT 采样

TCP实现时必须使用 Karn 算法 118544.118549 来采集RTT样本,因此不能根据TCP重传的数据包来生成RTT,当只有重传的数据包使用 Timestamp Option 时,才可以根据重传数据包来生成RTT。

TCP实现必须在同一时间生成一个RTT,然而使用 Timestamp Option 时,每一个ACK报文都可以作为一个RTT样本。RFC 1323: TCP Extensions for High Performance 建议 使用大拥塞窗口的TCP连接应该为每个数据窗口使用多个RTT样本来避免RTT估计时的混叠效应(aliasing effects).

在统计、信号处理和相关领域中,混叠是指取样信号被还原成连续信号时产生彼此交叠而失真的现象。 当混叠发生时,原始信号无法从取样信号还原。 而混叠可能发生在时域上,称做时间混叠,或是发生在频域上,被称作空间混叠

TCP 实现必须为每个RTT进行至少一次RTT测量。

对于较小的拥塞窗口,研究表明,测量每个报文并不会使得RTT更加准确。

1.1.3 Clock Granularity

没有必要使用 Clock Granularity 用于 RTT 与 RTTVAR 的计算。如果 K × R T T V A R K\times RTTVAR K×RTTVAR 项计算值等于0,则方差必须四舍五入到 G 秒。即上述公式

R T O : = S R T T + m a x ( G , 4 ∗ R T T V A R ) RTO := SRTT + max(G, 4 * RTTVAR) RTO:=SRTT+max(G,4RTTVAR)

经验表明,更细粒度的 G 值(如 小于等于100 ms)使得算法有更好的性能。

Note: Jacobson, V. , Congestion Avoidance and Control 列出了其他技巧用于在 粗粒度的时钟(Coarse Granularity Timer) 下也能得出比较精确的结果,这些技巧在现代TCP实现中往往是必备的。

1.1.4 管理 RTO Timer

TCP 实现必须管理重传计时器(Retransmission Timers) ,以确保报文不会过早被重传。

以下是推荐的RTO管理算法:

Note: 计时器和计时器的状态是相互独立的,关闭计时器并不意味着清空计时器状态

  1. 每次包含数据的数据包被发送(也包括重传的),如果计时器没有运行,则启动它。并以上述(1.1.1)算法进行计时器状态初始化。
  2. 当所有发送的数据都被确认时,则关闭计时器
  3. 当收到确认新数据的ACK时,则重启计时器

当重传计时器超时时,执行以下步骤:

  1. 重传最早的没有收到确认的报文 ( The earliest segment that has not been acknowledged by TCP Receiver.)

  2. 主机必须将 将RTO 设置为两倍 即 R T O : = R T O × 2 RTO :=RTO\times 2 RTO:=RTO×2 (退避计时器 , back off the timer)

    上述说过,RTO有一个最大值,RTO的最大值至少是60秒 (1.1.1)

  3. 开启重传计时器,计时器将在 R T O × 2 RTO\times 2 RTO×2秒后超时

  4. 如果在三次握手期间等待对SYN的ACK报文超时了,并且TCP实现所使用的RTO小于3秒,那么当数据开始传输时,RTO必须重新初始化为3秒(即在三次握手之后)

注意,当重传成功后(即,成功发送并收到ACK),将产生新的RTT,此时执行1.1.1中所述的算法。

TCP实现 可能重置 RTT 和 RTTVAR (即清空计时器状态)在若干次对计时器进行back off (退避)后,因为退避若干次后的RTO可能不再适用于当前的网络环境。重置后,应该使用首次连接建立连接时的算法进行初始化。

1.1.5 安全性考虑

TCP需要在重传未确认前等待一段时间,攻击者可以通过让数据包延迟从而让TCP发送端计算出很大的RTO,然而添加额外的延迟往往与报文丢失的情况相吻合,因此,除了丢弃部分 TCP 连接数据包外,我们很难看出攻击者能从这种可能对网络造成更大破坏的攻击中获得什么。

攻击者还可能造成TCP节点在网络拥堵条件下更加频繁地发送数据——伪造ACK报文。从而使得发送方将RTO降低到不安全的值。能做到如此是极为困难的,需要正确地构建ACK报文,这就需要攻击者实时监测数据流。相比于其他的攻击手段,这种攻击造成的影响不大。因为实际是,网络确实拥堵,TCP发送端仍然会因为拥塞导致收到不正确的数据包而 back off 其超时计时器。

back off : R T O : = 2 × R T O RTO := 2\times RTO RTO:=2×RTO

1.1.6 为什么建议使用更小的值初始化RTO

选择合适的初始RTO是需要考虑两个竞态条件的:

1. RTO 应该足够大,来避免网络的故障或者拥堵的时间段(几秒?几十秒?),因为如果RTO不够大,那么你发送的数据包还是会因为网络问题而重传
2. RTO一方面应该足够小,以确保接收方尽快地收到丢失的报文。

其他之前的文档习惯将TCP的RTO初始值设置为3s,那么这里(RFC 6298)呼吁将改值设置为更小的1s。

RFC 1122: Requirements for Internet Hosts - Communication Layers & RFC 2988: Computing TCP’s Retransmission Timer

原因如下:

  • 现代普通的通信网络的速率与之前 定义RTO为3s时代的最牛逼(State-of-the-art) 的网络相比,已经快了不少。

    那个时代,按照1122、2988文档发布时间来看,指的是(1989-2000年)

  • 大规模调查研究发现,现代 97.5 % 97.5\% 97.5% 的网络连接的 RTT (往返时间)小于1s。

  • 另外,研究还发现 三次握手(3WHS)的期间报文重传几率大概为 2 % 2\% 2% ,所以减少RTO的初始值连接性能的显著提升。

  • Tuning TCP Parameters for the 21st Century 的报告显示,只有约 2.5 % 2.5\% 2.5% 的TCP连接的RTO值大于 1s。对于这些连接,1 秒的初始 RTO 可保证在连接建立期间进行一次重传(无论是否需要)。

    当出现这种情况时,这里要求在数据传输阶段恢复到 3 秒的初始 RTO。对于这种性能较低或环境较差的的网络,显然 1秒的RTO势必会造成不必要的重传,但其实影响不大。

  • 17
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天晴丶SnowCrystal

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值