4、快速重传与超时重传:两种重传的抓包特征

这一章咱们聊聊重传的两种“姿势”——快速重传和超时重传。很多刚入门的朋友容易把这两者混为一谈,觉得都是“丢包了重发一次”。其实不然。我在项目里见过不少案例,明明是快速重传能解决的问题,硬生生拖成了超时重传,结果业务延迟飙升。搞清楚它们的区别,你抓包排障时就能一眼看出问题根因。

核心一句话:快速重传是“我怀疑你丢了,赶紧补发”;超时重传是“我等太久了,肯定丢了,必须重来”。

4.1 快速重传机制详解

快速重传,英文叫 Fast Retransmit。它的触发条件不是等超时,而是收到重复的 ACK。

举个例子。发送方发了包 1、2、3、4。接收方收到了 1,回复 ACK=2。接着收到了 3,但没收到 2,所以它还是回复 ACK=2。再收到 4,依然没收到 2,继续回复 ACK=2。当发送方连续收到 3 个相同的 ACK(即 ACK=2 出现三次),它就知道包 2 丢了。这时候不等超时计时器,直接重发包 2。

我个人习惯把快速重传理解为“基于反馈的快速补救”。它依赖接收方的重复确认来驱动,不需要等待漫长的 RTO 到期。所以延迟更低,对交互型应用更友好。

小提示:Linux 内核默认的重复 ACK 阈值是 3。你可以通过修改 /proc/sys/net/ipv4/tcp_early_retrans 来调整,但一般不建议动它。

4.2 超时重传(RTO)计算

超时重传就简单粗暴了——发送方发出一个包,启动一个计时器。如果计时器到期还没收到 ACK,它就认为包丢了,直接重传。

这个计时器的时长就是 RTO(Retransmission Timeout)。RTO 不是固定的,它基于 RTT(Round Trip Time)动态计算。你想想看,如果网络延迟是 10ms,RTO 设成 1 秒,那效率得多低?反过来,如果网络延迟是 200ms,RTO 设成 100ms,那就会频繁误判丢包。

Linux 内核里 RTO 的计算公式大致是:

SRTT = (1 - α) × SRTT + α × RTT
RTTVAR = (1 - β) × RTTVAR + β × |SRTT - RTT|
RTO = SRTT + max(G, 4 × RTTVAR)

其中 α 通常取 1/8,β 取 1/4,G 是时钟粒度。说白了,RTO 就是平滑后的 RTT 加上 4 倍的 RTT 偏差。这样能适应网络抖动。

我记得有一次排查一个跨国链路的慢问题,发现 RTO 被计算得特别大,导致一次丢包要等 3 秒才重传。后来发现是中间路由器引入了巨大的抖动,RTTVAR 被撑大了。嗯,这种情况调内核参数效果有限,得从网络路径上找原因。

注意:RTO 有下限。Linux 内核中 RTO 最小值为 200ms(HZ=100 时),最大值为 120 秒。即使你的 RTT 只有 1ms,RTO 也不会低于 200ms。这是为了防止虚假超时。

4.3 两种重传的抓包特征

抓包时怎么区分这两种重传?看特征就行。我带你过一遍 Wireshark 里的典型画面。

快速重传的抓包特征

  • 前置条件:连续出现 3 个或以上的重复 ACK。
  • 重传包:Seq 号与之前某个包相同,且与上一个包的 Seq 不连续。
  • 时间间隔:重传包与原始包之间的时间差通常很小(毫秒级),远小于 RTO。
  • Wireshark 标记:Wireshark 会在 Packet List 面板中标注 "[TCP Fast Retransmission]",一眼就能看到。

举个例子,你可能会看到这样的抓包序列:

1. 192.168.1.1 → 192.168.1.2  Seq=1, Len=100
2. 192.168.1.2 → 192.168.1.1  ACK=101
3. 192.168.1.1 → 192.168.1.2  Seq=101, Len=100
4. 192.168.1.2 → 192.168.1.1  ACK=101   ← 重复 ACK #1
5. 192.168.1.1 → 192.168.1.2  Seq=201, Len=100
6. 192.168.1.2 → 192.168.1.1  ACK=101   ← 重复 ACK #2
7. 192.168.1.1 → 192.168.1.2  Seq=301, Len=100
8. 192.168.1.2 → 192.168.1.1  ACK=101   ← 重复 ACK #3
9. 192.168.1.1 → 192.168.1.2  Seq=101, Len=100  ← [TCP Fast Retransmission]

超时重传的抓包特征

  • 前置条件:没有重复 ACK,或者重复 ACK 数量不足。
  • 重传包:Seq 号与之前某个包相同。
  • 时间间隔:重传包与原始包之间的时间差较大,通常接近或等于 RTO 值。
  • Wireshark 标记:显示 "[TCP Retransmission]",没有 "Fast" 字样。
  • 伴随现象:超时重传后,通常会触发拥塞控制,cwnd 会大幅降低。

抓包看起来像这样:

1. 192.168.1.1 → 192.168.1.2  Seq=1, Len=100
   (等待 200ms... 没有 ACK 回来)
2. 192.168.1.1 → 192.168.1.2  Seq=1, Len=100  ← [TCP Retransmission]

4.4 两种重传的对比

对比维度 快速重传 超时重传
触发条件 收到 3 个重复 ACK RTO 计时器到期
响应速度 快(毫秒级) 慢(通常 ≥ 200ms)
对拥塞控制的影响 触发快速恢复,cwnd 减半 触发慢启动,cwnd 降至 1
Wireshark 标记 [TCP Fast Retransmission] [TCP Retransmission]
常见原因 轻微丢包、乱序 严重拥塞、链路中断、接收端宕机

我曾经遇到过一个案例:某业务频繁出现超时重传,但网络延迟和丢包率都正常。抓包一看,发现是接收端应用程序处理太慢,导致 TCP 接收缓冲区满,无法回复 ACK。发送方等不到 ACK,只能超时重传。这种情况调网络没用,得优化应用代码。

4.5 知识体系图:两种重传的决策流程

下面这张图帮你理清 TCP 在收到 ACK 或超时时的决策逻辑:

TCP 重传决策流程 发送数据包 收到 ACK? (等待事件触发) 是 检查 ACK 序号 是否重复? 重复 ACK ≥ 3? 是 快速重传 + 快速恢复 否 正常处理 ACK 更新窗口、发送新数据 否(超时) 超时重传 + 慢启动 快速重传由重复 ACK 驱动,超时重传由计时器驱动。两者触发的拥塞控制策略不同。

4.6 实战排障建议

抓包时看到快速重传,别太紧张。少量快速重传是正常的,网络里偶尔丢个包很正常。但如果快速重传占比超过 1%,或者频繁出现,那就要排查了。

看到超时重传,就要警惕了。超时重传意味着 TCP 的“最后防线”被触发了,通常伴随严重的性能下降。我建议你按以下步骤排查:

  1. 先看 RTO 值:在 Wireshark 里用 tcp.analysis.retransmission 过滤,查看重传包的时间戳,计算 RTO 是否异常。
  2. 再看 RTT:用 tcp.analysis.ack_rtt 查看 ACK 的往返时间,判断是网络延迟大还是抖动大。
  3. 最后看接收端:如果网络正常,那问题大概率在接收端——应用程序没及时读取数据,导致窗口关闭。

我的习惯:在 Wireshark 里设置两列自定义列——tcp.analysis.retransmission 和 tcp.analysis.fast_retransmission。这样一眼就能看出哪些包是重传,哪种重传。排障效率提升不少。