SACK/DSACK 频繁出现不表示网络故障,而是TCP纠错机制正常工作;需关注重传模式、DSACK重复性及RTO超时占比,结合tcpdump、ss和内核参数(如tcp_sack、tcp_reordering)综合判断与优化。

为什么看到大量 SACK/DSACK 不代表网络有问题
tcpdump 里频繁出现 SACK 和 DSACK 是 TCP 正常纠错机制在工作,尤其在高丢包率、乱序严重或接收窗口受限的链路上。业务没异常,说明重传及时、恢复快,SACK 已经在起作用——它本身不是问题,而是“问题被妥善处理了”的证据。真正要关注的是重传是否集中在某类包(如首包、尾包)、DSACK 是否反复指向同一段数据(暗示发送端重复发包),或重传间隔是否接近 RTO(说明超时重传开始主导,SACK 失效)。
哪些内核参数影响 SACK 行为和重传效率
Linux 默认开启 SACK,但以下参数决定它能否高效工作:
-
net.ipv4.tcp_sack = 1:必须开启,禁用后退到慢速的累计 ACK 重传 -
net.ipv4.tcp_dsack = 1:建议开启,帮助识别重复发送或接收端 DUP,避免误判丢包 -
net.ipv4.tcp_reordering:默认 3,表示允许接收端最大乱序程度;若实际乱序超过该值,会触发过早重传(Fast Retransmit 误触发);可观察TCP reno fastretrans或TCP sack reneging计数器升高来判断是否需调大(如设为 5–8) -
net.ipv4.tcp_slow_start_after_idle = 0:防止连接空闲后重置 cwnd,避免突发流量下因慢启动导致连续丢包和 SACK 激增
如何确认是 SACK 有效重传还是 RTO 超时重传
仅靠 tcpdump 看 [SACK] 标记不够,得结合时间戳和重传模式判断:
- 用
tcpdump -nni eth0 'tcp[tcpflags] & (tcp-syn|tcp-fin|tcp-rst) != 0 or tcp[12] & 0xf0 > 0x40'过滤出带选项的包,重点看SACK和重传包的序列号是否匹配已知丢失段 - 检查重传包是否紧随三个重复 ACK 出现(即 Fast Retransmit),这是 SACK 主导的标志;若重传发生在首个 ACK 后 >RTO 时间,则是超时重传,SACK 已失效
- 用
ss -i查看单个连接的retrans、retransmits、sacked字段,对比sacked占比;若sacked > retransmits * 0.8,说明 SACK 处理了绝大多数丢包
业务正常时还值得调优吗?重点关注哪几处
值得,尤其当 RTT 波动大、跨运营商或使用弱无线链路时。优化收益不在“修复故障”,而在降低重传延迟、提升吞吐稳定性:
- 不要盲目调大
tcp_reordering,超过实际乱序程度会掩盖真实丢包,导致 RTO 延长;先用tcptrace -r或 Wireshark 的 TCP Stream Graph 观察乱序分布 - 若 DSACK 高频出现且
tcp_dsack_ignore未启用,考虑加net.ipv4.tcp_dsack_ignore = 1(5.10+ 内核),忽略由接收端 DUP 引起的 DSACK,减少干扰 - 确保
net.ipv4.tcp_timestamps = 1开启,否则 PAWS 机制失效,可能引发旧包被误认为新包,间接导致 SACK 信息错乱
最易被忽略的是应用层行为:比如小包突发、无节制的 write() 调用压垮接收端缓冲区,造成伪乱序,此时调参不如控制发包节奏或增大 rmem_max。










