重传触发场景:丢包、乱序、窗口满、拥塞控制导致的延迟重传

说到重传,很多人第一反应就是“丢包了”。但实际抓包分析时你会发现,重传的触发远不止丢包这么简单。我个人习惯把重传触发场景分成四类:丢包、乱序、窗口满、拥塞控制导致的延迟重传。这四种场景在网络上表现完全不同,定位方法也不一样。

你想想看,如果一上来就盯着重传计数看,很容易被误导。我见过不少运维同学,看到重传就喊“丢包了”,结果查了半天发现是乱序导致的伪重传。嗯,咱们今天就把这四种场景掰开揉碎了讲清楚。

核心观点:重传不一定是丢包,乱序和窗口满也会触发重传。区分这四种场景,是定位网络性能问题的第一步。

重传触发场景分类 重传触发场景 丢包 乱序 窗口满 拥塞控制延迟重传 典型特征 • RTO 超时 • 快速重传(3次DupACK) • 序列号空洞 典型特征 • 无重传但序列号跳跃 • 后续包正常到达 • 延迟抖动小 典型特征 • 接收窗口为0 • 零窗口探测 • 应用层处理慢 典型特征 • 拥塞窗口收缩 • 慢启动/拥塞避免 • 延迟重传而非立即

丢包触发的重传

丢包是最直观的重传触发场景。说白了,就是发送方发了数据包,接收方没收到。TCP 靠两种机制来发现丢包:超时重传(RTO)和快速重传(Fast Retransmit)。

超时重传很好理解——发送方启动一个定时器,如果在 RTO(Retransmission Timeout)时间内没收到 ACK,就认为包丢了,直接重传。RTO 的初始值一般是 1 秒,但实际中会根据 RTT 动态调整。我记得有一次排查线上问题,发现 RTO 被放大到了 3 秒多,导致业务感知到明显的卡顿。

快速重传则更聪明一些。当接收方收到乱序包时,会立即回复一个重复 ACK(DupACK),告诉发送方“我还在等某个序列号”。发送方连续收到 3 个 DupACK 后,不等超时就直接重传。这个机制大大缩短了重传等待时间。

实战技巧:抓包时看到连续 3 个以上 DupACK,基本可以判定发生了丢包。但要注意,如果 DupACK 数量很少(1-2 个),可能是乱序而非丢包。

乱序触发的伪重传

乱序是个很有意思的场景。数据包在网络中走了不同的路径,到达顺序和发送顺序不一致。接收方收到乱序包后,会触发 DupACK,发送方看到 DupACK 可能误判为丢包,从而发起不必要的重传。

我在项目中遇到过这样一个案例:某 CDN 节点到源站的链路做了多路径负载均衡,结果包经常乱序到达。抓包一看,DupACK 满天飞,重传率飙到了 5% 以上。但实际丢包率几乎为零。这就是典型的伪重传。

怎么区分丢包和乱序?我个人习惯看两个指标:

  • DupACK 的分布:丢包时 DupACK 会持续出现,直到重传包到达;乱序时 DupACK 出现几次后,原始包就正常到达了。
  • 延迟抖动:乱序场景下延迟抖动通常较小,而丢包场景下 RTT 会明显增大。

避坑指南:我曾经因为没区分乱序和丢包,花了整整两天排查一个“假丢包”问题。后来发现是网卡的多队列 RSS 导致包被分发到不同 CPU 核处理,产生了乱序。调整了 RSS 哈希策略后,重传率直接降到了 0.1% 以下。

窗口满触发的零窗口探测

窗口满这个场景很多人容易忽略。接收方的接收窗口(rwnd)为 0 时,发送方不能再发送数据。但发送方需要定期发送零窗口探测包(Zero Window Probe),询问接收方“窗口开了没”。

如果接收方一直不回复,或者回复的窗口还是 0,发送方就会不断重传探测包。这种重传不是丢包导致的,而是应用层处理速度跟不上导致的。

我建议你在排查重传问题时,先看看接收窗口的变化曲线。如果窗口经常降到 0,说明应用层消费数据的速度太慢。这时候优化重传没有意义,应该去优化应用层的处理逻辑。

场景 触发条件 重传类型 定位方法
丢包 RTO 超时或 3 次 DupACK 超时重传 / 快速重传 抓包看序列号空洞
乱序 多路径导致包到达顺序错乱 伪重传(误判) 看 DupACK 数量和延迟抖动
窗口满 接收窗口为 0 零窗口探测重传 看接收窗口曲线
拥塞控制延迟重传 拥塞窗口收缩,延迟发送 延迟重传(非立即) 看拥塞窗口变化和 RTT

拥塞控制导致的延迟重传

这个场景最隐蔽。拥塞控制算法(如 Cubic、BBR)会根据网络状态动态调整发送速率。当检测到网络拥塞时,拥塞窗口(cwnd)会收缩,发送方会主动延迟发送数据。

但问题来了——延迟发送可能导致某些包在发送队列里等太久,超过了应用层的超时阈值,从而触发应用层的重传。这种重传不是 TCP 协议栈发起的,而是应用层自己重试的。

说白了,拥塞控制导致的延迟重传,本质上是协议栈的“减速”和应用层的“超时”之间的矛盾。我见过一个极端案例:某视频直播平台使用 Cubic 算法,在弱网环境下 cwnd 收缩到只有 2 个 MSS,导致数据发送延迟从 10ms 飙升到 500ms。应用层设置的超时是 200ms,结果大量触发应用层重传,反而加剧了网络拥塞。

关键洞察:拥塞控制导致的延迟重传,往往伴随着 RTT 增大和 cwnd 收缩。抓包时如果看到重传间隔不规律(不是固定的 RTO),且 cwnd 曲线在下降,基本可以判定是拥塞控制导致的。

四种场景的快速定位方法

讲完了四种场景,咱们来点实战的。我总结了一套快速定位流程,你可以在排查问题时直接套用:

  1. 先看重传类型:是超时重传还是快速重传?超时重传大概率是丢包,快速重传可能是丢包也可能是乱序。
  2. 再看 DupACK 数量:连续 3 个以上 DupACK 且后续有重传包,是丢包;DupACK 出现几次后原始包到达,是乱序。
  3. 检查接收窗口:如果 rwnd 经常为 0,窗口满的可能性大。
  4. 分析拥塞窗口:如果 cwnd 在重传前有明显收缩,且 RTT 增大,拥塞控制导致的延迟重传可能性高。

实用工具:我个人习惯用 tcpdump + Wireshark 的“分析→TCP 流图→时间序列(tcptrace)”功能,可以直观看到序列号、窗口、重传的对应关系。另外,Linux 下的 ss -ti 命令可以实时查看每个连接的 cwnd 和 rwnd。