한국어English日本語简体中文繁體中文DeutschไทยTiếng ViệtРусскийPortuguês (Brasil)EspañolBahasa Indonesia

游戏卡顿白皮书 › 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。

出处

  1. Thin-streams and TCP Linux kernel
    像游戏这样稀疏发送的 thin stream,快速重传很难生效,只能依赖较长的超时;判定标准是已发出未确认的数据包(in-flight)少于 4 个
  2. RFC 5681: TCP Congestion Control IETF
    收到第三个重复 ACK 时快速重传
  3. RFC 8985: The RACK-TLP Loss Detection Algorithm for TCP IETF
    RACK 根据后发的包已送达来判断丢包;TLP 等待时间为 2·SRTT(只有一个未确认包时,再加上延迟 ACK 的余量)
  4. include/net/tcp.h Linux kernel
    TCP_RTO_MIN 200 ms,thin stream 判定(in-flight 包少于 4 个)和 6 次线性重试
  5. tcp: remove thin_dupack feature Linux kernel
    2017 年 1 月删除 thin_dupack(Linux 4.11),并说明由 RACK 承担其作用
  6. IP Sysctl Linux kernel
    tcp_thin_linear_timeouts:thin stream 连接最多 6 次 RTO 不翻倍(默认关闭)
  7. tcp(7) — Linux manual page Linux man-pages
    TCP_NODELAY 关闭 Nagle 算法
  8. net/ipv4/proc.c Linux kernel
    nstat 中的计数器名 TCPTimeouts、TCPFastRetrans、TCPLossProbes、TCPLossProbeRecovery
  9. net/ipv4/tcp_timer.c Linux kernel
    重传定时器(RTO)到期时 TCPTimeouts 增加
  10. SNMP counter Linux kernel
    TcpExtTCPFastRetrans(不处于 Loss 状态时的重传),TcpExtTCPLossProbes(发送 TLP)、TcpExtTCPLossProbeRecovery(通过 TLP 恢复丢包)
  11. ss(8) — Linux manual page iproute2
    ss -i 的 rto(ms)、backoff(RTO 翻倍的次数)

相关原因

同一层:TCP 重传的根本原因

其他层中同样导致“卡住”的原因

查看含图示和实验的原卡片