游戏卡顿白皮书 › L8 Socket 与协议
TCP 队头阻塞 Head-of-line blocking
原因 ID sk-hol · 主责 研发团队·服务器开发 · 配合 研发团队·客户端开发
在含图示和实验的完整版中打开此卡片 →
TCP 为了保证顺序,在重新收到丢失的那个包之前,不会把后面已经到达的数据包交给游戏。
起因 一个数据包丢失 → 结果 后面的包已经到了,却在接收缓冲区里等着 → 画面表现 先停顿,然后一下子全部放出来,表现为快进
- 症状
- 卡住, 快进
- 因素
- 丢包, 停顿
- 谁会遇到
- 只有我
- 何时出现
- 偶尔随机
- 负责方
- 主责 研发团队·服务器开发 · 配合 研发团队·客户端开发
- 研发团队要做的事
- 服务器:实时位置用 UDP,只有必不可少的内容走可靠传输,拆成多条流。客户端:网络处理改成与服务器相同的方式(UDP、分通道)。
- 数值参考
- 丢一个包至少停顿往返时间 + α,连重传也丢了则会停顿几百 ms 到几秒。
- 监控图上
- 断流后集中到达 · 每个连接的接收量、重传次数
- 查看位置
- 用服务器侧抓包(tcpdump、Wireshark)查看该玩家连接中的重传包及其前后的空档;全服看 nstat -az 中 TcpRetransSegs 的增量
- 确认依据
- 停顿区间以一个包的重传开始,重传包到达后,积压的数据被一次性处理(接收量先是 0,然后集中涌入)
- 排除依据
- 用 UDP 通信的游戏不适用。没有重传却停顿,看服务器 tick(“Tick 超出预算”)
- 确认手段
- 运维工具即可确认(无需游戏代码)
出处
- RFC 9293: Transmission Control Protocol (TCP) IETF
TCP 是可靠的、保证顺序的字节流服务 - RFC 5681: TCP Congestion Control IETF
通过 3 个重复 ACK 检测丢包并快速重传,否则等待重传定时器 - RFC 6298: Computing TCP's Retransmission Timer IETF
重传定时器每超时一次就翻倍的退避 - net/ipv4/proc.c (Linux v6.12) Linux kernel
nstat 显示的计数器名:Tcp 组的 RetransSegs(重传的报文段数)
相关原因
同一层:L8 Socket 与协议
其他层中同样导致“卡住”的原因
查看含图示和实验的原卡片