TCP 的那些事 | RTO

时间:2024-03-16 17:11:56

文章《TCP 的那些事 | 快速重传》、《TCP 的那些事 | SACK》及《TCP的那些事 | D-SACK》讲解了TCP的快速重传机制、SACK机制以及D-SACK机制。TCP超时与重传中最重要的部分就是对一个给定连接的往返时间RTT(Round-Trip Time)的测量。由于路由器和网络流量均会变化,RTT这个时间可能经常会发生变化,如果测量出来RTT,那么发送端大致就知道需要多久进行重传,这个重传时间就是RTO(Retransmission TimeOut)。

如果Timeout时间设置的太长,重发就慢,丢了老半天才重发,没有效率,性能差;设置太短,会导致可能并没有丢就重发,于是重发的就快,会增加网络拥塞,导致更多的超时,更多的超时导致更多的重发。

最初的TCP规范使用低通过滤器来更新一个被平滑的RTT估计器(记为R),公式如下:

TCP 的那些事 | RTO

其中,α是一个推荐值为0.9的平滑因子。每次进行新测量的时候,这个被平滑的RTT将得到更新。每个新估计的90%来自前一个估计(为M),而10%则取自新的测量(公式右边的R)。

该算法在给定这个随RTT的变化而变化的平滑因子的条件下,RFC 793推荐的重传超时时间RTO(Retransmission TimeOut)的值为:

TCP 的那些事 | RTO

其中,β是一个推荐值为2的时延离散因子。

但是当RTT变化范围很大时,使用上述方法无法跟上这种变化,从而引起不必要的重传:当网络已经处于饱和状态时,不必要的重传会增加网络的负载,对网络而言这就像在火上浇油一样。

因此,RFC793给出了如下的SRTT(Smoothed RTT)的计算公式:

SRTT = α * SRTT+ (1- α) * RTT

其中,α 取值在0.8 到 0.9

RTO的计算公式如下:

RTO = min(UBOUND,  max (LBOUND,   β * SRTT))

UBOUND是最大的timeout时间,上限值

LBOUND是最小的timeout时间,下限值

β 值一般在1.3到2.0之间

上述计算公式需要面临一个问题:RTT怎么计算?是用第一次发数据的时间和Ack回来的时间做RTT样本值,还是用重传的时间和ACK回来的时间做RTT样本值。

TCP 的那些事 | RTO

1. 用第一次发数据的时间和Ack回来的时间做RTT样本值。但是对于图1(a)的情况(Ack没有及时回来,发送端进行了重传,但是后续Ack又回来了),存在计算值偏大的问题

2. 用重传时间和Ack回来的时间做RTT样本值。但是对于如图1(b)所示的情况(在重传包后不久就收到Ack)存在计算值偏小的问题

Karn's algorithm

针对RTT计算的问题,Karn's algorithm提出如下解决方法:不把重传的报文进行采样,于是就不用纠结重传和Ack之间的关系了。

但是这个方法存在的问题也很明显:如果网络突然发生剧烈变化,产生了很大的延时,但是由于之前的RTO很小,网络变动后又没有重新计算RTO,那么这个延时会导致重传之前所有的报文,网络情况本身就不好,又重传了很多报文,进而形成了恶性循环。

为了解决这个问题,Karn's algorithm算法采用了如下测量:只要重传,就将RTO翻倍。这个策略在具有高丢包率的网络环境中可以很好的平衡效率和性能。但是这个策略太死板,不能根据实际情况进行变化。

Jacobson / Karels Algorithm

前面两种算法用的都是“加权移动平均”,这种方法最大的毛病就是如果RTT有一个大的波动的话,很难被发现,因为被平滑掉了(这个也是加权平均的优点)。Jacobson / Karels Algorithm引入了最新的RTT的采样和平滑过的SRTT的差距做因子来计算。 公式如下:

SRTT = SRTT + α (RTT – SRTT) 

DevRTT = (1-β)*DevRTT + β*(|RTT-SRTT|) 

RTO= µ * SRTT + ∂ *DevRTT

其中,DevRTT(Deviation RTT),是SRTT和RTT的差距(加权移动平均)在Linux下,α = 0.125,β = 0.25, μ = 1,∂ = 4 ,这个算法在被用在今天的TCP协议中。

 

参考资料

1. Karn's algorithm

2. TCP 的那些事儿(下)

3. 《TCP/IP详解 卷1》

4. Computing TCP's Retransmission Timer

5. TCP congestion control

TCP 的那些事 | RTO
扫描二维码,关注“清远的梦呓”公众号,在手机端查看文章