首页 / 内容指南 / 当前文章

Linux TCP重传率高与Duplicate ACK:丢包、乱序和RTO排查指南

发布于 2026-08-26 · xieyipai.com 编辑部

监控显示 TCP retransmission 飙升,抓包出现 Duplicate ACK、Fast Retransmission 或 Retransmission,应用却只感知到下载变慢、请求尾延迟升高甚至偶发超时。看到重传并不能直接判定“网络丢包”。接收端在序列空间出现缺口时会发送重复 ACK,真实丢包、路径乱序、数据包复制、抓包点遗漏以及网卡分段/合并卸载都可能产生相似迹象;如果没有足够 ACK 反馈,发送端还会等动态 RTO 到期后重传。

本文目录(32 节)

先定义重传指标口径

确认监控使用的是主机级累计计数、单位时间增量、连接级 tcp_info,还是抓包工具的分析标记。不同口径不能直接比较。主机级重传上升可能由少数大流量连接贡献,也可能因连接数增加而自然增加。

同时看每秒发送段数、重传段数、连接数、吞吐和请求延迟,计算比例与绝对值。只看一个累计 RetransSegs 会在服务运行越久时越大。

固定一条问题连接

记录五元组、进程、网络命名空间、开始/结束时间和业务请求 ID:

SRC_IP:SRC_PORT -> DST_IP:DST_PORT / TCP
PID=
NETNS=
REQUEST_ID=

在容器、NAT 和负载均衡环境中,五元组会逐段变化。分别记录应用容器、宿主机、边缘和后端看到的连接,避免把不同 NAT 后连接当成一条。

TCP为何需要重传

RFC 9293 规定 TCP 通过序列号与累计确认实现可靠字节流。发送端跟踪最早未确认序列和下一发送序列;数据或 ACK 因错误、拥塞或路径故障丢失时,发送端必须重传以保证交付。

少量重传是可靠传输机制工作的一部分。问题在于重传比例、恢复耗时和业务影响是否超出基线,而不是追求任何网络中绝对为零。

Duplicate ACK表示什么

接收端收到高于当前期望序列的报文,说明序列空间出现缺口,会立即确认仍然期望的序列号。多个后续段到达时,可能产生多个相同 ACK。

重复 ACK 说明接收端见到了乱序后的数据,但不单独证明缺失段永久丢失。原段可能稍后到达,只是走了更慢路径。

Fast Retransmit如何触发

RFC 5681 描述的快速重传通常在发送端收到三个 Duplicate ACK 后,推断某个段丢失并在 RTO 到期前重传。随后快速恢复与拥塞窗口调整参与控制发送速率。

抓包标注 Fast Retransmission 应与 ACK 序列、SACK block 和发送端 ss -ti 状态一起看。分析器的标签是启发式判断,不是内核决策日志。

RTO重传与快速重传不同

当 ACK 反馈不足,例如尾部最后一个段丢失、双向路径严重中断或窗口很小,发送端可能无法收集三个重复 ACK,只能等待 Retransmission Timeout。RFC 6298 规定 RTO 根据平滑 RTT 和 RTT 方差动态计算,并在超时后退避。

RTO 通常对尾延迟影响更明显。多个近似指数退避间隔的重传,比紧邻 Duplicate ACK 的重传更像超时恢复。

用ss查看连接级内核状态

在发送端连接仍存在时执行:

ss -tinp dst 198.51.100.10

关注 retrans、rto、rtt/rttvar、cwnd、ssthresh、bytes_sent、bytes_acked、delivery rate 和 send/receive queue。不同内核版本输出字段可能不同,应结合当前 ss 版本解释。

保存多次时间序列比单次截图更有价值。不要修改 socket 或终止连接只为方便查看。

用nstat看主机级趋势

nstat -az | grep -E 'TcpRetransSegs|TcpExtTCPTimeouts|TcpExtTCPLostRetransmit|TcpExtTCPFastRetrans'

内核版本和计数器名称可能不同。先采集基线,再在固定时间窗比较增量;容器网络命名空间也可能有独立统计。主机总量只能定位“哪台机器异常”,不能证明哪条路径丢包。

抓包必须选择正确位置

发送端应用前、宿主机物理接口、负载均衡前后和接收端看到的报文不同。尽量在两端同一时间同步抓包,并用五元组、序列号和时间对齐。

tcpdump -i eth0 -s 0 -w trace.pcap 'host 198.51.100.10 and tcp port 443'

限制目标、接口、时长和文件大小。抓包可能含业务数据,应加密保存、限制访问并按期限删除。

单端抓包为何会误报重传

抓包进程可能因 CPU、磁盘或 ring buffer 不足丢包;它没看到原始段,却看到了后续重传,于是分析器标记“重传”。检查 tcpdump 结束时的 packets dropped by kernel 和网卡丢弃计数。

只有接收端也缺少原始段,或发送端内核计数/ACK 序列支持,才能把分析标记升级为真实重传证据。

TSO/GSO/GRO/LRO的抓包伪象

发送端 TSO/GSO 可能让抓包看到尚未由网卡切分的大段,接收端 GRO/LRO 可能把多个包合并后交给内核。抓包点在卸载前后会呈现不同长度、顺序和 checksum 状态。

不要看到“bad checksum”或大于 MTU 的本机抓包就直接判定线上报文损坏。必要时在维护窗口对单接口受控关闭相关 offload 做对照,操作前评估 CPU 和吞吐影响,完成后恢复。

真实丢包的常见位置

物理链路误码、交换机端口拥塞、主机 RX/TX ring 溢出、qdisc 丢弃、防火墙队列、虚拟交换机、隧道、负载均衡和对端网卡都可能丢包。逐跳收集接口 errors/drops、队列深度和拥塞计数。

不要因为发送端只显示一次 retrans 就直接归因运营商。证据应指出原段在哪一跳仍存在、下一跳开始消失。

用ethtool检查网卡计数

ip -s link show dev eth0
ethtool -S eth0

关注 CRC、missed、no buffer、ring drop、timeout 和队列相关计数,但驱动字段名称不同。对比事件前后增量并结合厂商文档解释,不能把所有非零历史计数都当作当前故障。

qdisc和软中断饱和

出口 qdisc 丢包、单队列拥塞、CPU softirq 处理不及或 RPS/RFS/IRQ 绑定失衡,都可能在主机内造成丢包。检查 tc -s qdisc、/proc/softirqs、CPU 利用率和队列分布。

优化队列和中断亲和性需要基准与回滚。不要直接放大所有 buffer;过大队列可能把丢包变成长延迟和 bufferbloat。

接收端应用慢不是普通丢包

接收端应用不读取会让 Recv-Q 增长并通告小窗口或零窗口。发送端停发或做 zero-window probe,与拥塞丢包恢复不同。已有窗口证据时应定位应用消费、线程池或 GC,而不是调大 RTO。

抓包中的 Window Full、ZeroWindow 和 Window Update 要与重传序列分别分析。

乱序为何触发Duplicate ACK

ECMP 多路径、链路聚合、隧道、无线网络、并行处理或路由收敛可能让后发段先到。轻微乱序能由 TCP/SACK 恢复,但持续深度乱序会触发不必要快速重传并降低拥塞窗口。

对比原段是否最终到达以及重传前后的路径、TTL 和时间差。不要把所有 Duplicate ACK 都计为物理丢包率。

多路径与流哈希问题

正常 ECMP 应尽量按流保持路径。如果哈希字段变化、链路聚合逐包分担或中间封装导致同一 TCP 流跨时延差异大的路径,就会显著乱序。

检查网络设备的负载分担模式、隧道外层哈希和链路延迟。修改哈希策略影响广泛,应先在单个测试流和维护窗口验证。

SACK提供哪些线索

Selective Acknowledgment 允许接收端告诉发送端已收到哪些非连续数据块,帮助恢复多个丢失段。抓包中 SACK block 可以显示缺口边界与后续到达范围。

检查 SYN 协商是否支持 SACK,并用序列图观察。不要仅因某些安全设备历史问题就全局关闭 SACK;这会降低多丢包恢复效率。

ACK路径也可能丢包

数据从 A 到 B 正常,但 B 返回 A 的 ACK 丢失,A 仍可能重传已被 B 收到的数据。接收端会识别重复段并再次 ACK。此时只看数据方向会错误归因。

双端抓包可证明 B 已发 ACK、A 未收到;随后检查反向路由、ACL、拥塞和非对称路径。

延迟ACK不要直接当故障

TCP 接收端可延迟 ACK 以减少开销,但规范限制不能过度延迟,并对乱序段建议立即 ACK。少量 ACK 间隔不是丢包证据。

只有 ACK 延迟异常、与 RTO/吞吐下降相关且双端时间同步可信时,才检查接收主机调度、CPU 和 TCP 实现。

NAT与负载均衡的超时

中间状态设备的连接表过期、容量耗尽或 failover 不同步,会让已有 TCP 流部分方向黑洞,产生连续 RTO 重传。检查设备会话命中、超时、HA 状态和丢弃原因。

不要简单增大所有状态超时;先确认业务连接生命周期与容量,防止状态表资源耗尽。

MTU问题和普通丢包如何区分

PMTU 黑洞常表现为握手和小包正常、超过某尺寸的数据反复重传,且与 MSS/路径特定。普通拥塞丢包通常不只锁定同一尺寸边界。

已有 PMTU 专项排查时,应通过序列长度、ICMP、MSS 和不同 payload 对照确认,而不是把任何大包重传都归为 MTU。

无线与移动网络的特点

无线链路底层可能重试、切换和乱序,TCP 只看到剩余丢包与 RTT 波动。采集信号质量、无线重传、切换事件和移动网络类型,与 TCP RTO 时间对齐。

不要仅在数据中心有线环境复现移动端问题,也不要用平均 RTT 掩盖高方差和尾部超时。

RTO为什么会指数退避

RFC 6298 要求 RTO 基于 SRTT 和 RTTVAR 计算,超时重传后采用退避,避免在拥塞或断路时不断加剧网络负载。因此一次丢包可能让后续等待越来越长。

不应通过随意缩短系统 RTO 来“加快恢复”。过于激进会制造伪重传和拥塞;应修复反馈丢失、路径或应用超时设计。

应用超时与内核重传谁先发生

应用的请求超时可能短于 TCP 完整重传恢复周期。应用先取消请求或关闭 socket,用户看到超时,而内核还曾尝试恢复。反之,连接池重用、重试策略也可能放大流量并造成更多拥塞。

把应用 deadline、代理 timeout、TCP RTO 序列和业务重试对齐,避免每层都独立重试形成风暴。

不要盲目修改tcp_retries参数

Linux sysctl 中的重传阈值影响连接故障判定,降低它可能让短暂抖动变成连接断开,提高它则延长故障感知。内核参数是全局或命名空间级影响,不能替代链路修复。

任何调整都需要明确内核版本、应用 SLA、测试、监控和回滚,禁止从网络帖子复制数值直接上生产。

推荐排查顺序

  1. 定义指标口径和异常时间窗。
  2. 固定一条连接、五元组、进程和网络命名空间。
  3. 保存发送端 ss -ti 与主机 nstat 增量。
  4. 同步采集双端受限抓包。
  5. 区分快速重传、RTO、乱序和窗口事件。
  6. 检查抓包丢包与 offload 伪象。
  7. 沿路径检查接口、队列、防火墙、NAT 和反向 ACK。
  8. 对齐应用 timeout/retry,完成受控修复与回归。

每一步保留同一时间基准,跨主机先确认时钟同步。

修复后的验收清单

重传绝对值与比例回到基线;P95/P99 延迟和吞吐恢复;发送端 rtt/rto/cwnd 稳定;双端抓包无持续序列缺口;接口和 qdisc 丢弃不增长;ACK 返回路径正常;应用不会因多层重试制造新负载。

还要做受控故障测试,证明监控能区分快速恢复、RTO 超时、零窗口和路径中断,而不是只发一个“网络异常”告警。

常见错误

  • 把所有 Duplicate ACK 都当成丢包。
  • 只用单端 Wireshark 标签下结论。
  • 忽略抓包自身丢包和 TSO/GRO 影响。
  • 只看主机累计 RetransSegs,不看增量与流量。
  • 把 ACK 反向路径故障归因数据发送端。
  • 直接放大队列或缩短 RTO。
  • 修改全局 TCP sysctl 而无回滚。
  • 应用、代理和客户端同时无限重试。

FAQ

三个Duplicate ACK一定表示真实丢包吗?

不一定。它们也可能由网络乱序或复制产生。发送端会按快速重传算法处理,但根因仍需双端序列和路径证据确认。

Wireshark显示Retransmission就能确定内核重传吗?

不能。分析器基于它看到的序列推断;抓包漏包、抓包位置和 offload 都可能误标。结合发送端 tcp_info/nstat 与接收端抓包验证。

Fast Retransmit和RTO哪个影响更大?

快速重传利用重复 ACK 较早恢复;RTO 要等待定时器到期并可能退避,通常对尾延迟影响更明显,但具体取决于 RTT、窗口与丢包位置。

把TCP重试次数调低能更快失败吗?

可能,但会把可恢复的短暂抖动变成连接错误,并影响所有相关连接。应先修复根因,再按 SLA 和内核文档做受控评估。

Recv-Q增长算网络丢包吗?

通常首先指向接收应用消费不及并可能触发窗口收缩。它与路径丢包是不同方向,应检查应用读取、CPU、线程和零窗口证据。

总结

Linux TCP 重传高不是单一故障类型。Duplicate ACK 可由丢包、乱序或复制引起,快速重传依赖 ACK 反馈,RTO 则在反馈不足时兜底并退避。固定单连接,结合 ss -ti、nstat、双端抓包、接口/队列计数与应用超时,排除抓包和 offload 伪象后,才能把问题定位到具体主机、链路或应用层,并在不破坏拥塞控制的前提下修复。

来源资料