ゲームラグ白書 › L12 データベース
DBのデッドロック Database deadlock
原因ID db-deadlock · 主担当 ゲーム開発チーム・サーバー開発 · 副担当 インフラチーム・DBインフラ
図と実験のあるメインページでこのカードを開く →
2つのトランザクション(ひとまとまりで処理されるDB操作)が互いに相手のロックした行を待つと、DBが片方を強制的に取り消します。
なぜ 取引Aはアイテム→通貨、Bは通貨→アイテムの順にロック → すると DBがデッドロックを検知して片方をロールバック → 画面では 取引・製作がときどき失敗、アイテムが元に戻る
- 症状
- 不発・ロールバック, 入力遅延
- 要因
- パケットロス, ストール
- 誰に起きるか
- 特定の機能だけ
- いつ
- 人が集中したとき, 特定の操作をしたとき
- 担当
- 主担当 ゲーム開発チーム・サーバー開発 · 副担当 インフラチーム・DBインフラ
- ゲーム開発チームの対応
- ロック順序の統一、トランザクションを短く、失敗時の自動再試行。
- インフラチームの対応
- デッドロック検知を有効にしておき、デッドロックの記録を収集して共有、検知を無効にしたMySQLサーバーはロック待ちの上限(デフォルト50秒)を短縮。
- 数値の目安
- 検知までに、MySQL(InnoDB)はほぼ即時、PostgreSQLはデフォルトで1秒、SQL Serverは最大5秒ほどかかります。その間、両方の要求が止まっています。同時要求が非常に多いためにMySQLの検知を無効にしているサーバーでは、ロック待ちの上限(デフォルト50秒)まで待ちます。
- グラフでは
- 不定期なスパイク · デッドロック数、取引失敗数
- 確認箇所
- MySQLはSHOW ENGINE INNODB STATUSのLATEST DETECTED DEADLOCK(直近の1件)、innodb_print_all_deadlocksを有効にするとエラーログに残るすべてのデッドロック、INFORMATION_SCHEMA.INNODB_METRICSのlock_deadlocksを確認。PostgreSQLはpg_stat_databaseのdeadlocks、SQL Serverはデフォルトで有効なsystem_healthセッションのxml_deadlock_reportを確認。ゲームサーバー側のエラーコードはMySQL 1213、PostgreSQL 40P01、SQL Server 1205
- 該当する場合
- 取引・製作の失敗時刻にデッドロック数が増え、記録された2つのトランザクションが同じテーブル群を互いに逆の順序でロックしている
- 該当しない場合
- デッドロック数は変わらないのに失敗するなら、ロック待ちの上限超過(MySQLエラー1205)かホットスポット(db-hot-row)
- 確認手段
- インフラのツールで確認(ゲームコード不要)
出典
- InnoDB Startup Options and System Variables MySQL
検知が有効なら(デフォルト)InnoDBはデッドロックを即座に検知してロールバック、innodb_lock_wait_timeoutのデフォルトは50秒 - Deadlock Detection MySQL
同時実行性が非常に高いと検知自体が遅くなることがあるため、無効にしてロック待ちの上限に任せることもある - Lock Management (PostgreSQL Documentation) PostgreSQL
deadlock_timeoutのデフォルトは1秒:この時間ロックを待ってから初めてデッドロックを検査 - Deadlocks guide Microsoft SQL Server
デッドロック検査のデフォルト間隔は5秒、デッドロックが頻発すると100msまで短縮、デフォルトで有効なsystem_healthセッションがxml_deadlock_reportを収集、犠牲になった側はエラー1205 - How to Minimize and Handle Deadlocks MySQL
複数の行・テーブルは常に同じ順序で更新する、失敗したら再試行、innodb_print_all_deadlocksですべてのデッドロックを記録 - InnoDB Standard Monitor and Lock Monitor Output MySQL
LATEST DETECTED DEADLOCK:直近のデッドロックの2つのトランザクション、保持したロック・待ったロック、ロールバックした側 - InnoDB INFORMATION_SCHEMA Metrics Table MySQL
INNODB_METRICSのlock_deadlocksカウンター(デフォルトで有効) - Server Error Message Reference MySQL
1213 ER_LOCK_DEADLOCK(デッドロック)、1205 ER_LOCK_WAIT_TIMEOUT(ロック待ちの上限超過) - The Cumulative Statistics System (PostgreSQL Documentation) PostgreSQL
pg_stat_databaseのdeadlocks:このDBで検知したデッドロックの数 - PostgreSQL Error Codes (PostgreSQL Documentation) PostgreSQL
40P01 deadlock_detected
あわせて読みたい原因
同じ層:L12 データベース
同じ症状(不発・ロールバック)を起こすほかの層の原因
図と実験のあるメインページでこのカードを見る