ゲームラグ白書 › L7 サーバーOS(カーネル)
接続待ちキュー(backlog)のあふれ Listen backlog / SYN queue overflow
原因ID so-backlog · 主担当 ゲーム開発チーム・サーバー開発 · 副担当 インフラチーム・サーバーインフラ, ゲーム開発チーム・クライアント開発
図と実験のあるメインページでこのカードを開く →
メンテ明けに数万人が同時に接続すると、カーネルの接続待ちキュー(backlog)があふれ、接続要求が破棄されます。
なぜ メンテ終了と同時に、ゲームサーバーがacceptで接続を処理する速度を上回る勢いで接続が殺到 → すると カーネルの接続待ちキュー(backlog。サーバーのコードがlistenに渡した値とカーネルの上限のうち小さいほう)が満杯 → 画面では 接続要求が破棄されて再試行が繰り返され、接続不可・無限ロード
- 症状
- 接続不可・無限ロード
- 要因
- パケットロス
- 誰に起きるか
- サーバー全体
- いつ
- 接続直後・メンテ明け
- 担当
- 主担当 ゲーム開発チーム・サーバー開発 · 副担当 インフラチーム・サーバーインフラ, ゲーム開発チーム・クライアント開発
- ゲーム開発チームの対応
- サーバー:コードでlistenに渡す値を増やす、接続を受け付けるスレッドがほかの処理で止まらないようにする、ログイン待機列の仕組み。クライアント:再試行の間隔を広げる(ランダムに分散)。
- インフラチームの対応
- カーネルのsomaxconnを増やす(サーバーのコードのlistenの値と両方を上げないと効果がない)、SYN Cookieを有効にしておく、あふれた回数の監視(nstatのTcpExtListenOverflows)。
- 数値の目安
- Linuxカーネルの上限(somaxconn)は5.4からデフォルト4,096(それ以前は128)ですが、サーバーのコードがlistenにそれより小さい値を渡すと、その値が上限になります。Linuxはキューが満杯になると、接続要求をエラーも返さずに黙って破棄します。クライアントのOSが1秒後から何度か再送するため、プレイヤーには「接続失敗」よりも長いロードに見えます。Windowsサーバーは拒否の応答を返すので、クライアントにはすぐに「接続失敗」と表示されます。
- グラフでは
- 接続直後・メンテ明けに急増 · 接続待ちキューのあふれ数(ListenOverflows)、接続試行数
- 確認箇所
- nstat -azでTcpExtListenOverflows・TcpExtListenDropsの増加量を確認し、ss -ltnでリッスンソケットのRecv-Q(acceptを待っている接続数)とSend-Q(backlogの上限)を比較
- 該当する場合
- 接続が殺到した時刻にListenOverflowsが増え、リッスンソケットのRecv-QがSend-Qの値に張り付いている
- 該当しない場合
- ListenOverflowsが増えていなければこの原因ではない。接続は確立したのにロードが終わらなければ「ログイン殺到とN+1クエリ」、ちょうど一定の人数で入れなくなるなら「ファイルディスクリプタの上限」
- 確認手段
- インフラのツールで確認(ゲームコード不要)
出典
- listen(2) — Linux manual page Linux man-pages
listenのbacklogはsomaxconnを超えると黙って切り詰められる、somaxconnのデフォルトは4,096(5.4から。以前は128)、キューが満杯のときは要求を無視してクライアントの再試行に任せることがある - IP Sysctl Linux kernel
tcp_syn_retries:接続要求(SYN)を、最初の再送待ちを1秒として何度か再送、tcp_abort_on_overflowはデフォルトで無効(あふれても拒否の応答を返さない)、tcp_syncookiesはデフォルトで有効 - listen function (winsock2.h) Microsoft
Windowsではキューが満杯になると、クライアントがWSAECONNREFUSEDエラーを受け取る - SNMP counter Linux kernel
TcpExtListenOverflows:acceptキューが満杯で接続要求(SYN)を破棄した回数、このときTcpExtListenDropsも一緒に増える - net/ipv4/tcp_diag.c (Linux v6.12) Linux kernel
ssのRecv-Q・Send-Qの値:リッスンソケットではacceptを待っている接続数とbacklogの上限、接続済みソケットではアプリがまだ読んでいないバイト数とACKを受け取っていない送信バイト数
あわせて読みたい原因
同じ層:L7 サーバーOS(カーネル)
同じ症状(接続不可・無限ロード)を起こすほかの層の原因
図と実験のあるメインページでこのカードを見る