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 或超时时的决策逻辑:
4.6 实战排障建议
抓包时看到快速重传,别太紧张。少量快速重传是正常的,网络里偶尔丢个包很正常。但如果快速重传占比超过 1%,或者频繁出现,那就要排查了。
看到超时重传,就要警惕了。超时重传意味着 TCP 的“最后防线”被触发了,通常伴随严重的性能下降。我建议你按以下步骤排查:
- 先看 RTO 值:在 Wireshark 里用
tcp.analysis.retransmission过滤,查看重传包的时间戳,计算 RTO 是否异常。 - 再看 RTT:用
tcp.analysis.ack_rtt查看 ACK 的往返时间,判断是网络延迟大还是抖动大。 - 最后看接收端:如果网络正常,那问题大概率在接收端——应用程序没及时读取数据,导致窗口关闭。
我的习惯:在 Wireshark 里设置两列自定义列——tcp.analysis.retransmission 和 tcp.analysis.fast_retransmission。这样一眼就能看出哪些包是重传,哪种重传。排障效率提升不少。