ゲームラグ白書 › L9 サーバーのゲームプロセス
デッドロック Deadlock
原因ID sp-deadlock · 主担当 ゲーム開発チーム・サーバー開発
図と実験のあるメインページでこのカードを開く →
2つのスレッドが互いに相手の取ったロックを待つと、永遠に止まったままになります。
なぜ スレッドAはロック1を取ったままロック2を、Bはロック2を取ったままロック1を待つ → すると 両方とも永遠に止まり、関連するスレッドも次々に止まる → 画面では サーバー全体が停止し、ウォッチドッグによる再起動で全員が切断
- 症状
- フリーズ, 切断
- 要因
- ストール
- 誰に起きるか
- サーバー全体, 特定の機能だけ
- いつ
- ときどきランダムに, 人が集中したとき
- 担当
- 主担当 ゲーム開発チーム・サーバー開発
- ゲーム開発チームの対応
- ロックを取る順序のルール、タイムアウト付きのロック、ウォッチドッグと停止した瞬間のスレッドダンプの記録。
- グラフでは
- 接続が一斉に切れる · 接続数、サーバーの送信量
- 確認箇所
- 止まっている間に全スレッドのコールスタックを取得。JVMはjstack(デッドロックを自動で検出して表示)、.NETはdotnet-stack、ネイティブのサーバーはgdbのthread apply all bt、またはgcoreでコアファイルを取っておき、再起動した後で分析
- 該当する場合
- 2つ以上のスレッドが、互いに相手の取ったロックを待つスタックのまま止まっており、その間プロセスのCPU使用率が0に近い
- 該当しない場合
- 止まっている間にスレッド1つがCPUを100%使って回り続けていれば無限ループ。各スレッドがDB・外部の応答を待っていれば、同期呼び出しかスレッドプールの枯渇の側
- 確認手段
- インフラのツールで確認(ゲームコード不要)
出典
- Runtime locking correctness validator Linux kernel
2つのロックを互いに逆の順序で取ると循環待ちでデッドロック(lock inversion deadlock)、Linuxカーネルはロックの順序を検査して事前に警告 - Liveness, Readiness, and Startup Probes Kubernetes
実行中なのに処理が進まないデッドロック状態をLiveness Probeで検知し、コンテナを再起動 - Diagnostic Tools (Java SE 21 Troubleshooting Guide) Oracle
jstackは実行中のJVMの全スレッドのスタックを出力し、デッドロックも検出して表示(Found one Java-level deadlock) - dotnet-stack diagnostic tool - .NET CLI Microsoft
.NETプロセスの全スレッドのマネージドスタックをキャプチャして出力 - Threads (Debugging with GDB) GNU Project
thread apply allで全スレッドに同じコマンド(bt:コールスタックの出力)を実行 - gcore(1) — Linux manual page gdb
実行中のプログラムのコアファイルを作成し、作成後もプログラムはそのまま実行を続ける
あわせて読みたい原因
同じ層:L9 サーバーのゲームプロセス
同じ症状(フリーズ)を起こすほかの層の原因
図と実験のあるメインページでこのカードを見る