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

游戏卡顿白皮书 › L8 Socket 与协议

Nagle 算法 + 延迟 ACK Nagle + delayed ACK (TCP_NODELAY off)

原因 ID sk-nagle · 主责 研发团队·服务器开发 · 配合 研发团队·客户端开发

在含图示和实验的完整版中打开此卡片 →

把小包攒起来再发的 Nagle 算法,和推迟发送 ACK 的延迟 ACK 叠加在一起,消息每拆开写一次,就会延迟 40~200 ms。

起因 没开 TCP_NODELAY,却把小消息拆成多次写入 → 结果 发送方在等 ACK,接收方却推迟发送 ACK → 画面表现 线路 ping 很低,所有操作却都固定地慢半拍,表现为操作延迟

症状
操作延迟
因素
延迟
谁会遇到
全服, 只有我
何时出现
一直, 做特定操作时
负责方
主责 研发团队·服务器开发 · 配合 研发团队·客户端开发
研发团队要做的事
服务器:开启 TCP_NODELAY;把一个 tick 内的消息攒起来一次写入;关闭接收方延迟 ACK 的办法(Linux 的 TCP_QUICKACK 只能短暂维持,Windows 要逐台 PC 改注册表)游戏无法可靠掌控,不要依赖。客户端:开启 TCP_NODELAY;把一帧内的消息攒起来一次写入。
数值参考
延迟 ACK 在 Linux 上通常为 40 ms(视情况最长 200 ms)。Windows 旧版本为 200 ms,新版本为 40 ms(Windows Server 2019 默认模板为 40 ms)。延迟 ACK 由接收方的操作系统决定,所以服务器开着 Nagle 拆分发送消息时,视接收端 PC 不同,每次可能延迟 40~200 ms。
监控图上
一直偏高 · 操作响应时间(游戏内 RTT)
查看位置
在服务器侧抓包(tcpdump、Wireshark)中查看请求与响应之间的间隔,确认服务器、客户端代码是否开启了 TCP_NODELAY
确认依据
线路 ping 很低,小包之间却反复出现 40 ms(Windows 旧版本为 200 ms)左右的空档,且空档在对方的 ACK 到达后立即结束。开启 TCP_NODELAY 后消失
排除依据
响应间隔与线路 ping 相近则不是这个原因。游戏服务器生成响应慢,看服务器处理(“消息队列积压”)
确认手段
运维工具即可确认(无需游戏代码)

出处

  1. RFC 9293: Transmission Control Protocol (TCP) IETF
    Nagle 在有未确认数据时把小数据攒起来;必须能按连接关闭;延迟 ACK 小于 0.5 秒;两者叠加的问题
  2. include/net/tcp.h (Linux v6.12) Linux kernel
    Linux 延迟 ACK 最小为 TCP_DELACK_MIN(HZ/25 = 40 ms),最大为 TCP_DELACK_MAX(HZ/5 = 200 ms)
  3. TCP improvements in the Windows network stack (IETF 98 TCPM) Microsoft
    Windows 把默认延迟 ACK 超时改为 40 ms(2017 年发布)
  4. TCP Templates for Windows Server 2019 – How to tune your Windows Server Transports (Advanced users only 😉) Microsoft
    Server 2019 模板:DelayedAckTimeout 40 ms,MaxSynRetransmissions 2,InitialRto 3000 ms
  5. Design issues - Sending small data segments over TCP with Winsock Microsoft
    旧版 Windows TCP 收到数据后会启动 200 ms 的延迟 ACK 定时器,而 Nagle 默认开启,小包要等 ACK;用 TCP_NODELAY 解决

相关原因

同一层:L8 Socket 与协议

其他层中同样导致“操作延迟”的原因

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