4、现代RTO计算方法:RTT的采样与平滑、RTT的偏差计算、RTO的计算公式、最小RTO与最大RTO的限制

聊完超时重传的基本概念,咱们得进入一个更核心的环节——RTO(Retransmission Timeout)到底怎么算?

说白了,RTO 就是发送方在发出数据包后,愿意等多久才认为它丢了。这个值设得太短,容易造成大量不必要的重传,浪费带宽;设得太长,应用层感知到的延迟就会飙升。我早年调优过一个跨国传输的服务,就是因为 RTO 默认值太保守,导致用户频繁抱怨卡顿。嗯,从那以后我对 RTO 的计算公式就格外上心。

现代 TCP 实现(比如 Linux 内核中的实现)已经不依赖静态配置了,而是通过动态采样 RTT,再经过平滑、偏差计算,最终得出一个自适应的 RTO。下面我们一步步拆开看。

4.1 RTT的采样与平滑

RTO 的基础是 RTT(Round-Trip Time),也就是数据包从发出去到收到确认所经历的时间。但网络环境是波动的,单次 RTT 样本不能直接拿来用——万一这次刚好碰上网络抖动呢?

所以 TCP 引入了指数加权移动平均(EWMA),对 RTT 做平滑处理。公式如下:

SRTT = (1 - α) × SRTT_old + α × RTT_sample

其中 α 是平滑因子,标准推荐值是 1/8(0.125)。这个值意味着新样本的权重不大,历史趋势占主导,能有效过滤掉瞬时噪声。

我的经验:α 值不是死的。在无线网络环境下,我建议适当调大 α(比如 0.2~0.3),让 SRTT 更快跟上信道变化。但别超过 0.5,否则平滑效果就没了。

4.2 RTT的偏差计算

光有平滑后的 SRTT 还不够。你想想看,如果网络延迟突然翻倍,SRTT 反应慢半拍,RTO 还是按老值算,那重传就会滞后。所以我们需要一个偏差量来兜底。

这个偏差叫 RTTVAR(RTT Variation),同样用 EWMA 方式计算:

RTTVAR = (1 - β) × RTTVAR_old + β × |SRTT - RTT_sample|

β 的推荐值是 1/4(0.25)。注意这里用的是绝对偏差,而不是方差——因为计算方差需要平方运算,在嵌入式或早期网络栈中开销太大。用绝对偏差是工程上的折中,效果已经足够好。

核心思路:RTTVAR 越大,说明网络越不稳定,RTO 就应该留出更多余量。

4.3 RTO的计算公式

有了 SRTT 和 RTTVAR,RTO 的计算就水到渠成了。RFC 6298 给出的标准公式是:

RTO = SRTT + max(G, 4 × RTTVAR)

这里 G 是时钟粒度(clock granularity),通常是 1ms 或 10ms。为什么要取 max?因为当 RTTVAR 很小时(比如局域网环境),4×RTTVAR 可能比时钟粒度还小,这时候用 G 兜底,避免 RTO 被截断得太小。

我举个例子你就明白了:

场景 SRTT (ms) RTTVAR (ms) 4×RTTVAR (ms) G (ms) RTO (ms)
局域网 1 0.1 0.4 1 2
跨洋链路 200 30 120 1 320
无线网络(抖动大) 100 50 200 1 300

你看,局域网场景下 4×RTTVAR 只有 0.4ms,比时钟粒度还小,所以 RTO 实际上是 SRTT + G = 2ms。这个设计很巧妙,避免了过于激进的超时。

4.4 最小RTO与最大RTO的限制

公式算出来的 RTO 还不能直接用——必须加上上下限。为什么?

  • 最小 RTO:防止 RTO 过小导致虚假重传。RFC 6298 建议下限为 1 秒。但现代操作系统普遍觉得 1 秒太保守了,Linux 默认是 200ms(可通过 tcp_rto_min 调整)。
  • 最大 RTO:防止重传间隔无限增长。标准上限是 60 秒。超过这个值,TCP 会认为连接已经彻底断了,直接放弃。
我曾经踩过的坑:在某个数据中心内部项目中,我把最小 RTO 改成了 50ms,想着内网延迟低,应该没问题。结果碰上了一次微突发拥塞,大量 SYN 包被误判为丢失,导致连接建立失败率飙升。后来我学乖了——内网环境至少保留 100ms 的下限,给拥塞控制留点缓冲。

最终 RTO 的取值逻辑可以总结为:

RTO_final = clamp(RTO_calculated, RTO_min, RTO_max)

其中 clamp 函数将值限制在 [RTO_min, RTO_max] 区间内。

4.5 整体计算流程

下面这张图把整个 RTO 计算链路串起来了,你可以对照着看:

现代RTO计算流程图 现代RTO计算流程 RTT采样 SRTT = (1-α)×SRTT + α×RTT RTTVAR = (1-β)×RTTVAR + β×|SRTT-RTT| RTO = SRTT + max(G, 4×RTTVAR) RTO_final = clamp(RTO, RTO_min, RTO_max) α=0.125, β=0.25, RTO_min=200ms(Linux), RTO_max=60s

整个流程走下来,你会发现 RTO 不是拍脑袋定的,而是基于实时网络状态动态调整的。SRTT 反映基线延迟,RTTVAR 反映抖动幅度,上下限则防止极端情况。这三者配合,才构成了现代 TCP 栈中可靠的超时重传基础。

一句话总结:RTO = 平滑RTT + 4倍偏差抖动 + 上下限保护。这个公式从 RFC 6298 沿用至今,是 TCP 可靠性的基石之一。