游戏卡顿白皮书 › TCP 重传的根本原因
thin stream 恢复慢 Thin streams fall back to RTO
原因 ID rt-thin · 主责 研发团队·服务器开发 · 配合 运维团队·系统运维, 研发团队·客户端开发
在含图示和实验的完整版中打开此卡片 →
像游戏这样稀疏地发小包时,还没等到“后续 3 个包”,RTO 就先到期了。同样的丢包,停顿时间比大流量传输长得多。
起因 包间隔在 100 ms 左右,已发出未确认的数据包(in-flight)只有寥寥几个 → 结果 攒够 3 个重复 ACK 要 300 ms 以上,RTO(ping + 200 ms)先触发;连续丢包则每次翻倍 → 画面表现 丢一次包卡住 0.3 秒左右,重传的包也丢了就卡住将近 1 秒,然后快进
- 症状
- 卡住, 快进
- 因素
- 丢包, 停顿
- 谁会遇到
- 只有我, 全服
- 何时出现
- 偶尔随机
- 负责方
- 主责 研发团队·服务器开发 · 配合 运维团队·系统运维, 研发团队·客户端开发
- 研发团队要做的事
- 服务器:开启 TCP_NODELAY(Nagle 开着时,RACK 没有后续数据包可用来判断);实时数据包改用基于 UDP 的自有重传。客户端:开启 TCP_NODELAY;实时数据包与服务器用同样的方式(UDP)。
- 运维团队要做的事
- 使用 RACK-TLP(新版 Linux 默认);用 tcp_thin_linear_timeouts 让连续 RTO 不再翻倍。
- 数值参考
- 包间隔 100 ms、ping 60 ms 时,到快速重传约需 360 ms(等后面 3 个包到达且其确认返回),RTO 约为 260 ms。用 RACK 时,下一个包的确认在约 160 ms 返回时就会立即重传。包间隔超过 200 ms 时,RACK 也不比 RTO 快。
- 监控图上
- 断流后集中到达 · 每个连接的接收量,RTO 超时次数
- 查看位置
- 比较 nstat 中 TcpExtTCPTimeouts(RTO 超时)、TcpExtTCPFastRetrans(快速重传)、TcpExtTCPLossProbes、TcpExtTCPLossProbeRecovery(TLP)的增量,用 ss -ti 看游戏连接的 rto、backoff。同时确认服务器的 net.ipv4.tcp_recovery、tcp_early_retrans、tcp_sack 取值
- 确认依据
- 重传中 RTO 超时多于快速重传,游戏连接经常出现 backoff 大于 0(正在经历 RTO)。停顿期间接收量为 0,恢复后集中涌入
- 排除依据
- 同一服务器上的大流量传输也同样长时间停顿,就是与连接形态无关的丢包问题。集中在缺少 SACK 和时间戳的连接上,看“中间设备剥离 TCP 选项”
- 确认手段
- 运维工具即可确认(无需游戏代码)
- 深入了解
- Linux 以前还有一个面向 thin stream、收到 1 个重复 ACK 就重传的选项(tcp_thin_dupack),2017 年已删除,现在由 RACK 承担这个作用。Nagle 开着(TCP_NODELAY 关闭)时,等待丢失包的确认期间也不发新包,RACK 没有后续数据包可用来判断,只能等到 RTO。
出处
- Thin-streams and TCP Linux kernel
像游戏这样稀疏发送的 thin stream,快速重传很难生效,只能依赖较长的超时;判定标准是已发出未确认的数据包(in-flight)少于 4 个 - RFC 5681: TCP Congestion Control IETF
收到第三个重复 ACK 时快速重传 - RFC 8985: The RACK-TLP Loss Detection Algorithm for TCP IETF
RACK 根据后发的包已送达来判断丢包;TLP 等待时间为 2·SRTT(只有一个未确认包时,再加上延迟 ACK 的余量) - include/net/tcp.h Linux kernel
TCP_RTO_MIN 200 ms,thin stream 判定(in-flight 包少于 4 个)和 6 次线性重试 - tcp: remove thin_dupack feature Linux kernel
2017 年 1 月删除 thin_dupack(Linux 4.11),并说明由 RACK 承担其作用 - IP Sysctl Linux kernel
tcp_thin_linear_timeouts:thin stream 连接最多 6 次 RTO 不翻倍(默认关闭) - tcp(7) — Linux manual page Linux man-pages
TCP_NODELAY 关闭 Nagle 算法 - net/ipv4/proc.c Linux kernel
nstat 中的计数器名 TCPTimeouts、TCPFastRetrans、TCPLossProbes、TCPLossProbeRecovery - net/ipv4/tcp_timer.c Linux kernel
重传定时器(RTO)到期时 TCPTimeouts 增加 - SNMP counter Linux kernel
TcpExtTCPFastRetrans(不处于 Loss 状态时的重传),TcpExtTCPLossProbes(发送 TLP)、TcpExtTCPLossProbeRecovery(通过 TLP 恢复丢包) - ss(8) — Linux manual page iproute2
ss -i 的 rto(ms)、backoff(RTO 翻倍的次数)
相关原因
同一层:TCP 重传的根本原因
其他层中同样导致“卡住”的原因
查看含图示和实验的原卡片