什么是 D-SACK
D-SACK(Duplicate SACK,RFC 2883)让接收方在 SACK 选项里明确指出“这段数据我重复收到了”。发送方据此可以区分两类完全不同的情况:真正的丢包需要重传与降窗,而伪重传(原包只是延迟到达,接收方重复确认触发了重传)或路径上的重复报文则不应被当成拥塞信号。Linux 的 net.ipv4.tcp_dsack 默认开启,它与 tcp_sack 一起工作。
基本信息
| 参数路径 | net.ipv4.tcp_dsack |
|---|---|
| 默认值 | 1(开启) |
| 依赖 | tcp_sack 需要开启,SACK 选项里才能携带重复段信息 |
| 规范 | RFC 2883,IPv4 与 IPv6 共用一份实现 |
| 生效范围 | 内核全局,修改后对新连接生效 |
| 观测 | nstat/nstat -az 的 TcpExt 计数、抓包看 SACK 选项 |
典型使用场景
- 排查“莫名重传”:区分伪重传与真丢包,避免误判链路质量
- 重复报文诊断:确认中间设备或隧道封装是否造成重复
- 拥塞控制评估:重复 SACK 反馈帮助内核修正 cwnd 回退幅度
- 弱网与长肥管道优化:减少不必要的降速,保持吞吐
- 与 tcp_sack 组合核对:确认两端与中间设备没有剥离 SACK 选项
查看与观察
查看与观察
sysctl net.ipv4.tcp_dsack # 当前取值
sysctl net.ipv4.tcp_sack # 依赖项是否开启
nstat -az 2>/dev/null | grep -i sack | head # 重传与 SACK 相关计数
ss -tin dst :443 | grep -m2 -o 'retrans:[0-9/]*' # 单连接重传次数
tcpdump -i eth0 -n 'tcp[tcpflags] & tcp-ack != 0' -c 20 -v # 看 SACK 选项是否出现
# 如需关闭(不推荐):sysctl -w net.ipv4.tcp_dsack=0计数与现象对照
| 现象 | 含义 | 处置 |
|---|---|---|
| 重传计数上升但无丢包证据 | 可能是伪重传 | 确认 D-SACK 与 SACK 是否生效 |
| 抓包看到重复序列号 | 路径重复报文 | 查中间设备与隧道配置 |
| SACK 选项完全不出现 | 中间设备剥离或被关闭 | 核对两端 sysctl 与设备策略 |
| 重传比例高且伴随超时 | 真实丢包 | 按拥塞与链路方向排查 |
这些参数属于“默认正确”的一类:除非有明确证据指向 SACK 相关异常,不建议为省事直接关掉,关闭后会削弱拥塞控制对丢包的判断能力。
nstat 的 TcpExt 计数是系统级累计值,判断趋势要看增量:先记录一个时间点,等几分钟再做差,才有可比性。
部分防火墙或负载均衡设备会重写或剥离 TCP 选项,导致 SACK/D-SACK 在链路上失效;出现“本机开着但看不到”时优先怀疑中间设备。