ゲームラグ白書 › L12 データベース
ログイン殺到とN+1クエリ Login storm, N+1 queries
原因ID db-login-storm · 主担当 ゲーム開発チーム・サーバー開発 · 副担当 インフラチーム・DBインフラ
図と実験のあるメインページでこのカードを開く →
キャラクター1体を読み込むたびに数十回の個別クエリを発行していると、数万人の同時ログインは数百万件のクエリになります。
なぜ キャラクターのロード時にアイテム・スキル・クエストを個別にクエリ → すると メンテ明けの同時ログインでクエリが急増 → 画面では ログインの無限ロード、プレイ中のユーザーの保存まで滞る
- 症状
- 接続不可・無限ロード, 入力遅延
- 要因
- ストール, 遅延
- 誰に起きるか
- サーバー全体
- いつ
- 接続直後・メンテ明け
- 担当
- 主担当 ゲーム開発チーム・サーバー開発 · 副担当 インフラチーム・DBインフラ
- ゲーム開発チームの対応
- まとめて1回で取得、ログイン待機列、キャッシュ、ORMの遅延ロードが生むクエリ数の点検。
- インフラチームの対応
- 呼び出し回数の多いクエリのランキングを出して共有、メンテ明けのログイン時間帯のクエリ数・コネクション数を監視。
- グラフでは
- 接続直後・メンテ明けに急増 · DBの秒間クエリ数、ログイン数
- 確認箇所
- メンテ明けのログイン数とDBの秒間クエリ数(MySQLはQuestionsの増加量)を重ねて、ログイン1件あたりのクエリ数を計算。呼び出し回数が上位のクエリは、MySQLはevents_statements_summary_by_digestのCOUNT_STAR、PostgreSQLはpg_stat_statementsのcallsで抽出
- 該当する場合
- ログイン1件あたりのクエリが数十件あり、上位のクエリがキャラクターID 1つで検索する同じ形の短いクエリばかり。アップデート後にログインあたりのクエリ数が増えたなら、そのアップデートが発端
- 該当しない場合
- ログインあたりのクエリ数は少ないのにクエリ1つ1つが遅いなら、コールドキャッシュ(db-cold-cache)かインデックス(db-no-index)
- 確認手段
- インフラのツールで確認(ゲームコード不要)
- もっと詳しく
- ORM(DBへのクエリを代わりに組み立ててくれるライブラリ)の遅延ロード(lazy loading)が、開発者も気づかないうちにこうしたクエリを生みます。開発サーバーではキャラクターが数体しかないので目立たず、本番の同時ログインで初めて表面化します。
出典
- Efficient Querying .NET
ORMの遅延ロードは項目ごとにクエリをもう1回ずつ送るN+1問題を生み、性能を大きく落とす、一度にまとめて読み込む方式(eager loading)を推奨 - pg_stat_statements — track statistics of SQL planning and execution PostgreSQL
ステートメントごとの実行回数(calls)と合計実行時間を集計し、呼び出しの多いクエリのランキングを出す - Performance Schema Statement Digests and Sampling MySQL
events_statements_summary_by_digestで同じ形のクエリをまとめ、回数・時間を集計 - Statement Summary Tables MySQL
サマリーテーブルのCOUNT_STAR(実行回数)・SUM_TIMER_WAIT(合計時間) - Server Status Variables MySQL
Questions:クライアントが送信したステートメントの数
あわせて読みたい原因
同じ層:L12 データベース
同じ症状(接続不可・無限ロード)を起こすほかの層の原因
図と実験のあるメインページでこのカードを見る