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

ゲームラグ白書 › 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と同程度ならこの原因ではない。ゲームサーバーが応答を作るのが遅ければ、サーバーの処理側(「メッセージキューの滞留」)
確認手段
インフラのツールで確認(ゲームコード不要)

出典

  1. RFC 9293: Transmission Control Protocol (TCP) IETF
    NagleはACKを受け取っていないデータがあると小さなデータをためておく、接続ごとに無効にできる必要がある、遅延ACKは0.5秒未満、両者がかみ合う問題
  2. include/net/tcp.h (Linux v6.12) Linux kernel
    Linuxの遅延ACKの最小はTCP_DELACK_MIN(HZ/25 = 40ms)、最大はTCP_DELACK_MAX(HZ/5 = 200ms)
  3. TCP improvements in the Windows network stack (IETF 98 TCPM) Microsoft
    Windowsのデフォルトの遅延ACKタイムアウトを40msに変更(2017年発表)
  4. 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
  5. Design issues - Sending small data segments over TCP with Winsock Microsoft
    以前のWindowsのTCPはデータを受け取ると200msの遅延ACKタイマーをセットし、Nagleはデフォルトで有効なので小さなパケットがACKを待つ、TCP_NODELAYで解決

あわせて読みたい原因

同じ層:L8 ソケットとプロトコル

同じ症状(入力遅延)を起こすほかの層の原因

図と実験のあるメインページでこのカードを見る