参考教材:TCP-IP Guide
基本概念
RTT: 发送一个数据包到收到对应的ACK,所花费的时间
RTO: 发送数据包,启动重传定时器,重传定时器到期所花费的时间,称为RTO
对于segment的重传,重传的时间RTO设定是非常重要的,如果设置太短,可能会导致并没有丢包而重传,如果设置太长了,可能因为等待ACK而浪费掉很多时间,牺牲传输的效率。从思想上来讲,其实我们还是希望重传的时间需要稍稍的大于RTT就可以了。但是这个RTT没有什么可以使用的定值,他是不断变化的。
我们只能动态的进行设置,所以RTO只能是更加RTT来进行动态的设置,看下前辈们研究的RTT的计算方法
经典的算法 RFC793
1. 首先计算一个平滑的RTT称置为SRTT, alpha是一个平滑因子,取值为0.8或者0.9
SRTT = ( ALPHA * SRTT ) + ((1-ALPHA) * RTT)
2. 基于SRTT,计算出对应的RTO
RTO = min[UBOUND,max[LBOUND,(BETA*SRTT)]
其中UBOUND是最大值,一般情况下为120s,LBOUND是最小重传值,一般情况下为1s,Beta取值为1.3~2.0. [RFC793]
其实这个算法,在目前Linux系统协议栈的实现中并没有使用了,原因是存在着一些不足之处,具体弊端没有认真研究,有文章指出不明确是使用第一次发送ACK的时间,还是使用重传ACK的时间采样RTT, 也有文章指出在RTT变化比较大的网络,性能表现非常不好... 总之有缺点
Jacobaon/Karels 算法
1988年,Van Jacobson和Karels在Congestion Avoidance and Control这篇论文中提出一种新的算法[RFC6298],
第一次RTO计算方法, 假设RTT = R
1. SRTT = R
2. RTTVAR = R/2
3. RTO = SRTT + max(G, K*RTTVAR) , K = 4
后续的RTO计算,假设当前的RTT为R'
RTTVAR = (1 - beta)*RTTVAR + beta*|SRTT - R'| *计算平滑RTT和真实RTT的差距,切记这个地方的SRTT是上一次的SRTT*
SRTT = (1 - alpha)*SRTT + alpha*R' * 计算平滑RTT*
RTO = SRTT + max(G, K*RTTVAR)
alpha = 1/8 beta = 1/4, 值得指出的是这个算法在目前的Linux协议栈中应用,多么伟大的一件事情。
趣味考题
在阅读各种资料中,竟然看到一份考题,让计算RTO,现在果真是细节决定成败啊,不过记忆公式那真是学生时代的事情了...先看题目:
假定TCP在开始建立连接时,发送方设定超时重传时间是RTO=6s。 (1)当发送方接到对方的连接确认报文段时,测量出RTT样本值为1.5s。试计算现在的RTO值。 (2)当发送方发送数据报文段并接收到确认时,测量出RTT样本值为2.5s。试计算现在的RTO值。
【答案】 根据RFC6298
RTT(1) = 1.5s
SRTT(1) = RTT(1) = 1.5s
RTTVAR(1) = 1.5/2 = 0.75
RTO = 1.5 + 4*0.75 = 4.5s 所以现在RTO的值为4.5s
接着计算第二步 RTT (2) = 2.5
RTTVAR(2) = 3/4 * 0.75 + 1/4 * |1.5 - 2.5| = 13/16
SRTT(2) = 7/8 *1.5 + 1/8*2.5 = 1.625
RTO = 1.625 + 4 * 13/16 = 4.875
Note: RFC6298 还有关于采样RTT和管理RTO定时器的topic,可以参考,后续可能会增加,相关部分!