2. TCP/IP协议栈中的超时与重传:TCP重传定时器、RTO计算原理、指数退避算法
TCP 协议通过超时与重传机制保证数据的可靠交付。当发送方发出数据段后,会启动一个重传定时器(Retransmission Timer),如果在定时器到期前未收到对应的 ACK,则判定该数据段丢失,触发重传。这一机制的核心在于如何合理设定超时时间(RTO,Retransmission Timeout),以及如何在连续丢包时避免网络雪崩。
核心要点: RTO 过短会导致大量不必要的重传(加剧拥塞),RTO 过长则降低吞吐量(链路空闲等待)。TCP 通过动态测量 RTT(Round-Trip Time)来实时调整 RTO,并配合指数退避算法应对持续丢包。
2.1 TCP 重传定时器体系
TCP 协议栈为每个活跃连接维护多个定时器,其中与超时重传直接相关的是 重传定时器。此外,坚持定时器(Persist Timer)、保活定时器(Keepalive Timer) 和 TIME_WAIT 定时器 也间接影响连接稳定性,但本章聚焦于重传场景。
| 定时器名称 | 触发条件 | 超时动作 | 与重传关系 |
|---|---|---|---|
| 重传定时器 | 发送数据段且未收到 ACK | 重传最早未确认的段,RTO 指数退避 | 核心机制 |
| 坚持定时器 | 收到零窗口通告后 | 发送 1 字节探测段,防止死锁 | 间接避免重传超时 |
| 保活定时器 | 连接长时间空闲(默认 2 小时) | 发送保活探测,判断对端是否存活 | 非重传场景 |
| TIME_WAIT 定时器 | 主动关闭连接进入 TIME_WAIT | 等待 2MSL 后释放资源 | 防止旧重传段干扰新连接 |
运维提示: 在 Linux 中,重传定时器的初始 RTO 由
tcp_rto_min(默认 200ms)和 tcp_rto_max(默认 120s)约束。实际 RTO 值通过 RTT 动态计算,但不会超出此范围。
2.2 RTO 计算原理
RTO 的计算基于对网络往返时间(RTT)的连续采样。TCP 使用 Smoothed RTT(SRTT) 和 RTT 偏差(RTTVAR) 两个变量来估算当前网络状态。标准算法(RFC 6298)的步骤如下:
- 首次测量: 当第一个 RTT 样本
R获得后,初始化SRTT = R,RTTVAR = R/2,RTO = SRTT + max(G, 4 × RTTVAR),其中G为时钟粒度(通常 1ms 或 10ms)。 - 后续更新: 每获得一个新 RTT 样本
R',按以下公式更新:
其中RTTVAR = (1 - β) × RTTVAR + β × |SRTT - R'| SRTT = (1 - α) × SRTT + α × R' RTO = SRTT + max(G, 4 × RTTVAR)α = 1/8,β = 1/4。 - 时钟补偿: 若 RTO 计算结果小于
tcp_rto_min,则取最小值;若大于tcp_rto_max,则取最大值。
注意: 当发生重传时,TCP 会使用 Karn 算法 忽略重传段的 RTT 样本,避免因重传导致的 RTT 测量歧义(无法区分原始 ACK 还是重传 ACK)。直到收到一个非重传段的 ACK 后,才恢复 RTT 采样。
2.3 指数退避算法
当重传定时器超时后,TCP 不会立即以相同 RTO 再次重传,而是采用 指数退避(Exponential Backoff) 策略:每次超时后,将 RTO 翻倍,直到达到上限 tcp_rto_max(Linux 默认 120 秒)。
- 退避公式:
RTO_new = min(RTO_old × 2, tcp_rto_max) - 退避次数: 通常最多退避到上限后保持,直到重传成功或达到最大重传次数(
tcp_retries1/tcp_retries2)。 - 恢复时机: 当收到一个非重传段的 ACK 后,RTO 立即恢复为当前 SRTT 计算值,不再使用退避值。
退避示例: 假设初始 RTO = 1s,连续超时 5 次,退避序列为:1s → 2s → 4s → 8s → 16s → 32s。若第 6 次仍超时,则保持 32s(假设 tcp_rto_max=120s,实际可继续翻倍至 64s、120s)。
2.4 重传与退避的协同策略
TCP 的重传行为并非孤立执行,而是与 拥塞控制 紧密耦合。当重传定时器超时时,TCP 不仅退避 RTO,还会触发拥塞控制状态机:
- 拥塞窗口重置: 将
cwnd降为 1 个 MSS(最大报文段长度),进入慢启动阶段。 - 慢启动阈值调整: 将
ssthresh设为当前cwnd的一半(至少 2 个 MSS)。 - 重传模式: 超时重传仅重传最早未确认的段,而非批量重传所有丢失段。
调优关联: 在 Linux 中,
tcp_retries1(默认 3)决定何时通知上层(如应用层)网络可能存在问题;tcp_retries2(默认 15)决定何时彻底断开连接。这两个参数直接影响应用层感知的“超时时间”。
2.5 关键参数速查表
| 参数名 | Linux 默认值 | 作用域 | 调优建议 |
|---|---|---|---|
tcp_rto_min |
200 ms | 全局/网络命名空间 | 低延迟网络可降至 100ms;高延迟卫星链路可升至 500ms |
tcp_rto_max |
120 s | 全局/网络命名空间 | 内网可降至 30s;公网建议保持默认 |
tcp_retries1 |
3 | 全局/网络命名空间 | 对延迟敏感的应用可降至 2 |
tcp_retries2 |
15 | 全局/网络命名空间 | 移动网络可增至 20;内网可降至 8 |
tcp_syn_retries |
6 | 全局/网络命名空间 | SYN 超时重传次数,公网建议保持 |
注意: 修改
tcp_rto_min 和 tcp_rto_max 会影响所有新建连接。若需对特定连接调优,应使用 setsockopt() 的 TCP_USER_TIMEOUT 选项,该选项可覆盖全局 RTO 上限。