Linux TCP 之 RTT 采集与 RTO 计算
我们来看看 Linux TCP 采集 RTT 的函数 tcp_rtt_estimator,看注释,充满了胶着。
但在那个谨慎的年代,这些意味着什么?
RTT 最初仅用于 RTO 的计算而不是用于调速,RTO 的计算存在两个问题,如果过估,影响效率,如果低估,则会造成无效重传,但这都不是大问题,大问题是 TCP ACK 只提供给你那么多信息,你能如何利用好它。
TCP ACK 时钟允许你测量 RTT,但你又如何基于它计算 RTO 呢。大数定律说了,采样越多,均值越稳定,方差趋于 0,可 VJ 算法又严重依赖方差(mdev 替代,不赘述)。
随着网络带宽增加,窗口增大,大数定律对统计数值的影响增大,这可怎么办?
VJ 的 rttvar 是一个计算容易得多的 “伪方差”,同时又能记录采样数值上下波动,但它同样受到大数定律的影响,换句话说,rttvar 的目的不是求一个最终值,而是求一个相对实时的当前时段平滑值,取当下窗口期的平滑值,以判断当前的网络状态。
最能抵消大数定律影响的就是取一个窗口期内最大的 mdev 作为 rttvar,因为只想取相对合理且谨慎的值,而不是想 “采样被平均”,这就是 Linux 现实的做法,保守谨慎,保证了可用性,直到现在还在运行,也就是我们看到的 tcp_rtt_estimator 代码。但 Linux 对 RTO_MIN 的定义确实是瞎 JB 乱搞。
链接 RTO Estimator for CCID-2 详细讨论了 Linux RTT 采样和 RTO 计算的各种其它情形,比如,在直觉上 RTT 的快速减小预示着 RTO 也要同步减小,但事实上按照 RTO = SRTT + 4 * RTTVAR 公式看,RTTVAR 由于 RTT 相对 SRTT 的大量减少而增大,系数 4 意味着 RTO 总是会增大。为了抵消这种不合理的 RTO 增加,算法调整了系数:
if (RTT < SRTT - mdev)
mdev' := 31/32 * mdev + 1/32 * |RTT - SRTT|
else
mdev' := 3/4 * mdev + 1/4 * |RTT - SRTT|
浙江温州皮鞋湿,下雨进水不会胖。