LASSIC Media らしくメディア
デッドロックとは|発生条件と回避の考え方
「システムの動作がときどき固まる、特定の処理が応答を返さなくなる——調査を依頼したら『デッドロックが起きています』という報告が上がってきた。言葉は聞いたことがあるが、それが何を指し、なぜ起きるのかがつかめない」。IT事業部でベンダーからの障害報告を受ける立場にいると、こうした場面に出会うことがあるのではないでしょうか。デッドロックは、複数の処理が同時に動くシステムで起こりうる典型的なトラブルのひとつです。画面に現れるわけではなく、しかも「いつも起きる」わけではなく特定の条件が重なったときにだけ発生するため、発注者やPMにとっては実態のつかみにくい現象になりがちでしょう。しかし、その仕組みを大まかにでも理解しておくと、報告された障害の深刻度や、再発防止にどんな対応が要るのかを判断しやすくなります。本記事では、特定の技術の設定手順ではなく、デッドロックとはそもそも何か、なぜ起きるのか(発生の条件)、どう避けるのかという考え方を、発注・運用の視点から順に整理していきます。専門用語をすべて覚える必要はありませんが、「なぜ処理が止まるのか」を大づかみにできていれば、ベンダーとの会話や再発防止策の検討がしやすくなるはずです。
デッドロックとは何か
デッドロックとは、複数の処理が互いに相手の使っている資源の解放を待ち合い、どちらも先に進めなくなってしまう状態を指します。ここでいう資源とは、データベースの特定のデータや、ファイル、メモリ上の領域など、同時に一つの処理しか使えないように「ロック(占有)」される対象のことです。処理が資源を正しく使うためにロックを取る仕組み自体は妥当な設計ですが、その取り方が噛み合わないと、お互いが相手の解放を待ったまま止まってしまうことがあります。
厄介なのは、デッドロックに陥った処理はエラーで終わるのではなく、応答を返さないまま待ち続けてしまう点です。利用者から見ると「画面が固まった」「処理が終わらない」という形で現れ、原因がデッドロックだとはすぐには分かりません。放置すれば待ち行列が積み上がり、周辺の処理まで巻き込んで影響が広がることもあるでしょう。だからこそ、起きたことを検知して知らせる仕組みと、そもそも起こしにくくする設計の両方が意味を持ちます。
典型的なのは、次のような場面です。処理Aが資源1を確保したうえで資源2も使おうとし、ほぼ同時に処理Bが資源2を確保したうえで資源1を使おうとする。すると、Aは「Bが資源2を放すのを待つ」、Bは「Aが資源1を放すのを待つ」という関係になり、両者が相手の完了を待ち続けて永遠に進めなくなります。これがデッドロックです。次の図は、この相互待ちの関係を単純化して示したものです。
この記事のポイント
- デッドロックとは、複数の処理が互いに相手の資源の解放を待ち合い、どちらも進めなくなる状態です。
- 相互排他・保持と待機・横取り不可・循環待ちという4つの条件がそろったときに発生します。
- ロックを取る順序をそろえる、待ち時間に上限を設けるなどの設計で発生を抑えられ、再現しにくいためログと再現条件の把握が対応の鍵になります。
デッドロックが起きる4つの条件
デッドロックは、次の4つの条件がすべて同時に満たされたときに発生するとされています。逆にいえば、このうちどれか一つでも崩せば、デッドロックは起こらなくなるという関係にあります。回避策を考えるうえでの土台になる考え方です。
| 条件 | 内容 |
|---|---|
| 相互排他 | ある資源は同時に一つの処理しか使えず、他の処理は使い終わるまで待つ必要がある、という前提です。 |
| 保持と待機 | ある資源を確保したまま、さらに別の資源が空くのを待つ状態が生じることを指します。 |
| 横取り不可 | いったん確保された資源を、他の処理が強制的に取り上げることはできず、持ち主が自ら手放すのを待つしかない状態です。 |
| 循環待ち | 処理どうしが輪のように「AはBを待ち、BはAを待つ」という待ち関係の循環を作ってしまう状態を指します。 |
この4条件は、コンピュータサイエンスでよく知られた整理の仕方です。細かな名称を暗記する必要はありませんが、「どれか一つを崩せば防げる」という発想は、後で述べる回避策の考え方に直結します。たとえば循環待ちを崩すために資源を確保する順序をそろえる、保持と待機を崩すために必要な資源をまとめて確保する、といった具合に、条件と対策が対応している点を押さえておくと理解が進みやすいでしょう。
実際のシステムでは、これら4条件のうち最も崩しやすいのが循環待ちだといわれます。資源を確保する順序をあらかじめ決めておけば、輪のような待ち関係は生まれないためです。一方で相互排他は、データの整合性を守るうえで欠かせない性質であり、無理に崩すと別の不具合を招きかねません。どの条件に手を入れるのが自社のシステムにとって現実的かは、扱うデータの性質や求められる整合性の水準によって変わってきます。対策を検討する際は、条件とその副作用の両方を見比べる姿勢が役立つでしょう。
身近な例で理解する
デッドロックは、日常の場面にたとえるとイメージしやすくなります。よく使われるのが、狭い一本道で車が対向してしまう状況です。両方の車が道の真ん中まで進んでしまい、互いに「相手が下がってくれないと進めない」と譲らずにいると、どちらも動けなくなります。どちらか一方が先に下がれば解消しますが、双方が待つ姿勢のままだと膠着が続きます。
もう一つの例が、二人で料理をしていて、一方が「まな板」を持ったまま「包丁」が空くのを待ち、もう一方が「包丁」を持ったまま「まな板」が空くのを待つ、という状況です。どちらも自分が持っているものを手放さずに相手のものを待っているため、作業が止まってしまいます。システムの中でも、これと同じことがデータやファイルといった資源をめぐって起きている、と考えると腑に落ちやすいでしょう。人間なら「じゃあ私が先に譲ります」と気を利かせられますが、プログラムはあらかじめ決めた手順どおりにしか動かないため、設計の段階で待ち合いが起きないように工夫しておく必要があります。
補足すると、デッドロックは関わる処理が二つとは限りません。三つ以上の処理が数珠つなぎに待ち合う形でも起こり得るのです。処理Aが処理Bを、処理Bが処理Cを、そして処理Cが処理Aを待つ、といった長い循環になると、原因の追跡はいっそう難しくなります。関係する処理が増えるほど、どこで輪が閉じているのかを特定する手間もかかるため、記録を残しておくことの重要性が増していきます。
デッドロックを避ける考え方
デッドロックへの対処は、大きく「そもそも起こさないようにする」方向と、「起きても検知して抜け出す」方向に分けられます。発注や設計方針の会話で出てくる代表的な考え方を挙げておきます。
ロックを取る順序をそろえる
複数の資源をロックする際に、すべての処理が同じ順番で確保するように統一すると、循環待ちが生じなくなります。先ほどの例でいえば、どの処理も「資源1を先に、資源2を後に」という順序で確保する決まりにしておけば、AとBが互いを待ち合う関係は生まれません。設計上もっとも基本的で効果の大きい考え方といえるでしょう。
待ち時間に上限を設ける(タイムアウト)
資源が空くのを待つ時間に上限を決めておき、一定時間を過ぎたらいったん処理を諦めて資源を手放す、という方法です。手放したうえで少し時間をずらして再試行すれば、膠着から抜け出せることがあります。根本的に発生をなくすものではありませんが、万一起きても長時間止まり続ける事態を避ける保険として組み込まれることが多い考え方です。
ロックの範囲と時間を小さくする
ロックする対象をできるだけ狭く、ロックしている時間をできるだけ短くすると、処理どうしが資源を取り合う機会そのものが減り、デッドロックの起きにくい設計になります。必要以上に広い範囲を長く占有しないという心がけは、性能の面でもよい影響をもたらすことが多いでしょう。
検知して自動で解消する仕組みを使う
データベース管理システムなどには、デッドロックを検知すると片方の処理を強制的に中断(ロールバック)して膠着を解く仕組みが備わっていることがあります。この場合、中断された処理は改めてやり直す前提になるため、アプリケーション側でも「やり直しても問題が起きないように作っておく」配慮が求められます。仕組みに任せきりにするのではなく、やり直しを想定した設計とセットで考えることが大切です。
ここまでの対策は、いずれも先に挙げた4条件のどれかを崩すという発想でつながっています。ロック順序の統一は循環待ちを、必要な資源をまとめて確保するやり方は保持と待機を、検知して中断する仕組みは横取り不可を、それぞれ崩す狙いを持っています。どれか一つの決め手に頼るより、発生を抑える設計を基本に据えつつ、万一に備えた仕組みを重ねておくのが現実的な進め方でしょう。提案を受けた際は、その対策がどの条件を崩す狙いなのかという観点で眺めると、全体像を把握しやすくなります。
発注・運用で意識したい観点
デッドロックは、発注者やPMの立場からも押さえておきたい特徴がいくつかあります。障害報告を受けたときの判断や、再発防止策の妥当性を見極める手がかりになります。
第一に、デッドロックは再現しにくいという性質があります。特定のタイミングで複数の処理が重なったときにだけ起きるため、テスト環境では再現せず、利用が増えた本番環境で初めて表面化することも珍しくないのです。「たまに固まる」という報告があった場合、その裏でデッドロックが起きている可能性も視野に入れておくと、調査の方向性を早めに定めやすくなります。
第二に、原因の特定にはログが欠かせません。いつ、どの処理が、どの資源を待っていたのかという記録が残っていないと、後から原因を追うのは困難です。発注の段階で、デッドロックを含む障害時のログをどこまで残すのか、検知したときにどう通知するのかを、運用設計の一部として確認しておくとよいでしょう。第三に、対策としてロック順序の統一やタイムアウトが提案された場合、それがどの条件を崩す狙いなのかを一度尋ねてみると、対策の妥当性を判断しやすくなります。再発防止は「起きた箇所を直す」だけでなく、同種の問題が他の処理でも起きないかという横展開まで含めて検討する価値があるでしょう。なお本記事は特定製品の設定手順ではなく、デッドロックという現象の考え方と回避の方針に焦点を当てています。個別の実装や設定を詰める段階では、対象とするデータベースやフレームワークの公式ドキュメント、実績のあるベンダーへの確認が別途必要になります。
また、再発防止の実効性を高めるうえでは、本番に近い同時実行の状況を作って試す負荷テストが有効です。デッドロックは処理が重なったときにだけ現れるため、単体の機能テストではすり抜けてしまいます。リリース前に、想定される同時アクセスや、バッチ処理と画面操作の重なりを模したテストを組み込んでおくと、本番で初めて発覚する事態を減らせるでしょう。テストの範囲や条件をどこまで作り込むかも、発注の段階で相談しておきたい論点のひとつです。あわせて、既存システムで過去に発生した箇所があれば、その再現条件を共有しておくと、調査と対策の精度が上がります。
まとめ
- デッドロックとは、複数の処理が互いに相手の資源の解放を待ち合い、どちらも進めなくなる状態です。
- 相互排他・保持と待機・横取り不可・循環待ちの4条件がそろうと発生し、どれか一つを崩せば防げます。
- 一本道で対向した車や、まな板と包丁を待ち合う二人にたとえると、相互待ちの構図がつかみやすくなります。
- ロックを取る順序の統一、待ち時間の上限(タイムアウト)、ロック範囲・時間の縮小、検知して解消する仕組みの活用が代表的な対策です。
- 再現しにくいためログと再現条件の把握が重要で、再発防止は横展開まで含めて検討する視点が求められます。
- 本記事は特定製品の設定手順ではなく、デッドロックという現象の考え方と回避の方針の整理を狙いとしています。
よくある質問
デッドロックとロック(排他制御)は違うものですか。
ロック(排他制御)は、複数の処理が同じ資源を同時に変更して不整合が起きないよう、一つの処理だけが使えるように占有する正しい仕組みです。デッドロックは、そのロックの取り方が噛み合わず、複数の処理が互いの解放を待ち合って動けなくなる異常な状態を指します。つまりロックは仕組み、デッドロックはその使い方が原因で起こるトラブル、という関係です。ロックそのものが悪いわけではなく、取る順序やタイミングの設計が課題になります。
デッドロックはどのようなときに表面化しやすいですか。
複数の処理が同時に動き、同じ資源を奪い合う場面で起こりやすくなります。利用者やアクセスが増えて処理の同時実行が増えたとき、特定のバッチ処理と画面操作が重なったときなどに表面化することが多い傾向です。特定のタイミングでしか起きないため、テスト環境では再現せず本番で初めて見つかることもあります。「負荷が高い時間帯にだけ固まる」といった報告は、デッドロックを疑う手がかりになり得ます。
デッドロックを完全になくすことはできますか。
発生の4条件のいずれかを崩す設計にすれば、原理的には防げます。もっとも実務では、ロック順序の統一などで発生を大きく抑えつつ、万一に備えてタイムアウトや検知・自動解消の仕組みを併用する、という多層的な備えが現実的です。「一切起きない」と言い切るより、起きにくくし、起きても長時間止まらず復旧できるようにしておく、という考え方が扱いやすいでしょう。
障害報告で「デッドロック」と言われたら、まず何を確認すべきですか。
まず、いつ・どの処理が・どの資源を待っていたのかというログが残っているかを確認するとよいでしょう。そのうえで、どの条件を崩す対策を採るのか(ロック順序の統一かタイムアウトの導入かなど)をベンダーに尋ね、同じ問題が他の処理でも起きないかという横展開の観点まで含めて再発防止を検討すると、場当たり的な対応になりにくくなります。ログが不足している場合は、今後のために記録の強化もあわせて相談しておくとよいでしょう。
著者:テレリモ総研編集部 鈴木 亮佑
LASSICでは、国内ニアショア開発体制を活かし、同時実行を前提としたシステムの設計・開発から、デッドロックを含む障害の調査、ロック設計やデータベース周りの見直し、ログ・監視体制の整備までを一貫して支援する体制です。再現しにくい不具合の原因調査や、再発防止策の横展開についてもご相談いただけます。要件定義の段階から実装、テスト、リリース後の運用・保守まで、工程を分けずに任せられる点も強みでしょう。原因の切り分けに迷う段階からでも、ご相談ください。
ご不明な点はお問い合わせフォームからもご連絡いただけます。