ゲームラグ白書 › L8 ソケットとプロトコル
Nagleアルゴリズム+遅延ACK Nagle + delayed ACK (TCP_NODELAY off)
原因ID sk-nagle · 主担当 ゲーム開発チーム・サーバー開発 · 副担当 ゲーム開発チーム・クライアント開発
図と実験のあるメインページでこのカードを開く →
小さなパケットをまとめて送るNagleアルゴリズムと、ACKを遅らせて送る遅延ACKがかみ合い、メッセージを分けて書き込むたびに40〜200msずつ遅延します。
なぜ TCP_NODELAYを有効にしないまま、小さなメッセージを分けて書き込む → すると 送信側はACKを待ち、受信側はACKを遅らせて送る → 画面では 回線のPingは低いのに、すべての操作が一様にもたつく入力遅延
症状 入力遅延
要因 遅延
誰に起きるか サーバー全体, 自分だけ
いつ 常に, 特定の操作をしたとき
担当 主担当 ゲーム開発チーム・サーバー開発 · 副担当 ゲーム開発チーム・クライアント開発
ゲーム開発チームの対応 サーバー:TCP_NODELAYを有効にする、1ティック分のメッセージをまとめて一度に書き込む、受信側の遅延ACKを無効にする方法(LinuxのTCP_QUICKACKは一時的にしか維持されない、WindowsはPCごとにレジストリを変更)はゲーム側で確実に制御できないので頼らない。クライアント:TCP_NODELAYを有効にする、1フレーム分のメッセージをまとめて一度に書き込む。
数値の目安 遅延ACKは、Linuxでは通常40ms(状況によって最大200ms)です。Windowsは以前のバージョンが200msで、最近のバージョンは40msです(Windows Server 2019のデフォルトテンプレートは40ms)。遅延ACKは受信側のOSが決めるため、サーバーがNagleを有効にしたままメッセージを分けて送ると、受信するPCによって40〜200msずつ遅延することがあります。
グラフでは 最初から常に高い · 操作の応答時間(ゲーム内のRTT)
確認箇所 サーバー側のパケットキャプチャ(tcpdump・Wireshark)でリクエストとレスポンスの間隔を確認し、サーバー・クライアントのコードがTCP_NODELAYを有効にしているかを確認 該当する場合 回線のPingは低いのに、小さなパケットの間に40ms(Windowsの以前のバージョンは200ms)前後の空白が繰り返し現れ、その空白は相手のACKが届いた直後に終わる。TCP_NODELAYを有効にすると消える 該当しない場合 応答の間隔が回線のPingと同程度ならこの原因ではない。ゲームサーバーが応答を作るのが遅ければ、サーバーの処理側(「メッセージキューの滞留」) 確認手段 インフラのツールで確認(ゲームコード不要)
出典 RFC 9293: Transmission Control Protocol (TCP) IETF NagleはACKを受け取っていないデータがあると小さなデータをためておく、接続ごとに無効にできる必要がある、遅延ACKは0.5秒未満、両者がかみ合う問題 include/net/tcp.h (Linux v6.12) Linux kernel Linuxの遅延ACKの最小はTCP_DELACK_MIN(HZ/25 = 40ms)、最大はTCP_DELACK_MAX(HZ/5 = 200ms) TCP improvements in the Windows network stack (IETF 98 TCPM) Microsoft Windowsのデフォルトの遅延ACKタイムアウトを40msに変更(2017年発表) TCP Templates for Windows Server 2019 – How to tune your Windows Server Transports (Advanced users only 😉) Microsoft Server 2019テンプレートのDelayedAckTimeout 40ms、MaxSynRetransmissions 2、InitialRto 3000ms Design issues - Sending small data segments over TCP with Winsock Microsoft 以前のWindowsのTCPはデータを受け取ると200msの遅延ACKタイマーをセットし、Nagleはデフォルトで有効なので小さなパケットがACKを待つ、TCP_NODELAYで解決
あわせて読みたい原因
同じ層:L8 ソケットとプロトコル
同じ症状(入力遅延)を起こすほかの層の原因
図と実験のあるメインページでこのカードを見る