ゲームラグ白書 › TCP再送の根本原因
ゼロウィンドウ(再送のように見える停止) Zero window, often mistaken for retransmission
原因ID rt-zero-window · 主担当 ゲーム開発チーム・クライアント開発 · 副担当 ゲーム開発チーム・サーバー開発, インフラチーム・サーバーインフラ
図と実験のあるメインページでこのカードを開く →
受信側のプログラムがソケットを読むのが間に合わず、バッファが満杯になると、送信側は送信を止めてゼロウィンドウプローブだけを送ります。回線の問題ではありません。
なぜ クライアントのフレームが止まる、サーバーのスレッドがブロックされるなどでソケットを読めない → すると 受信ウィンドウが0になり、送信側は送信を止めてプローブだけを送る(間隔がだんだん延びる) → 画面では 止まった後に早送り。パケットキャプチャに「ZeroWindow」が見え、パケットロスはない
- 症状
- フリーズ, 早送り
- 要因
- ストール
- 誰に起きるか
- 自分だけ, サーバー全体
- いつ
- 人が集中したとき, ときどきランダムに
- 担当
- 主担当 ゲーム開発チーム・クライアント開発 · 副担当 ゲーム開発チーム・サーバー開発, インフラチーム・サーバーインフラ
- ゲーム開発チームの対応
- パケットキャプチャでZeroWindowを送った側(ソケットを読めていない側)をまず確認、ネットワークの受信は別スレッドで読み続ける、受信バッファを適切なサイズに。クライアント:ロード・GCのようなフレーム停止の原因を解消。サーバー:ソケットを読むスレッドがブロックされる原因を解消。
- インフラチームの対応
- サーバーのnstat TcpExtTCPToZeroWindowAdv(サーバーが受信ウィンドウを0と通知した回数)を監視に追加(増えればサーバー側の問題なのでサーバー開発に連絡)、サーバー側のパケットキャプチャを提供。
- グラフでは
- 途切れた後にまとめて到着 · 接続ごとの受信量、ゼロウィンドウの回数
- 確認箇所
- パケットキャプチャでWiresharkのフィルターtcp.analysis.zero_windowを使い、ウィンドウ0を通知した側を探す。サーバーのnstatでは、TcpExtTCPToZeroWindowAdv(サーバーがウィンドウ0を通知)とTcpExtTCPWinProbe(相手のウィンドウ0に対してプローブを送信)を分けて確認し、サーバーのソケットのRecv-Q(ssで表示される、プログラムがまだ読んでいないバイト数)を確認
- 該当する場合
- 止まっている間に再送はなく、ゼロウィンドウとプローブだけがやり取りされる。サーバーのTcpExtTCPToZeroWindowAdvやサーバーのソケットのRecv-Qが増えるならサーバーの読み出しが間に合っていない。TcpExtTCPWinProbeが増えるならクライアントの読み出しが間に合っていない
- 該当しない場合
- キャプチャにゼロウィンドウがなく、同じデータが再度送られているなら、原因はパケットロスか不要な再送
- 確認手段
- インフラのツールで確認(ゲームコード不要)
- 実際の事例
- Roblox 2021: Robloxの73時間障害:サービスディスカバリ(Consul)クラスターでの競合
出典
- RFC 9293: Transmission Control Protocol (TCP) IETF
受信ウィンドウが0なら送信側はゼロウィンドウプローブを送り、プローブの間隔は指数的に延ばす - 7.5. TCP Analysis Wireshark
TCP ZeroWindow:受信側がウィンドウ0を通知し、送信側に送信を止めさせたパケット - Display Filter Reference: Transmission Control Protocol Wireshark
tcp.analysis.zero_window、tcp.analysis.zero_window_probeの表示フィルター - SNMP counter Linux kernel
TcpExtTCPToZeroWindowAdv:受信ウィンドウを0以外の値から0に変えて通知した回数 - net/ipv4/proc.c Linux kernel
nstatに表示されるカウンター名TCPToZeroWindowAdv・TCPWinProbe - net/ipv4/tcp_output.c Linux kernel
TCPWinProbe:相手の受信ウィンドウが0のときに送るプローブ(tcp_send_probe0)ごとに増加 - net/ipv4/tcp_diag.c Linux kernel
ssのRecv-Qは、確立済みの接続では、受信したがプログラムがまだ読んでいないバイト数
あわせて読みたい原因
同じ層:TCP再送の根本原因
同じ症状(フリーズ)を起こすほかの層の原因
図と実験のあるメインページでこのカードを見る