TL

2相コミット(2PC)と分散トランザクション

複数DBにまたがる更新を、全部成功か全部取消にそろえる仕組みがわかります。prepare/commit の2段階と、なぜブロッキングが起きるのかを原理から押さえます。

応用2相コミット分散トランザクションコーディネータ整合性データベース最終更新: 2026-06-21
TL;DR要点だけ先に
  • 1.2PC はコーディネータが全参加者に prepare で投票を募り、全員 YES なら commit、1人でも NO なら abort して原子性をそろえる。
  • 2.prepare で YES を返した参加者はコミットもアボートもできず待つしかないため、コーディネータ障害でロックを抱えたまま固まるブロッキング問題がある。
  • 3.3PC は pre-commit 段階を挟んでブロッキングを緩和するが、ネットワーク分断には弱く、実務では Saga や Paxos/Raft 系合意が選ばれることが多い。

分散トランザクションが難しい理由

単一DB内なら、トランザクションは WAL(先行書き込みログ)と1つのコミットレコードで原子的に確定できます。ところが更新対象が複数のDBやサービスにまたがると、各ノードはそれぞれ独立にコミット/ロールバックを判断するため、「Aだけ成功してBは失敗」という中途半端な状態が起こりえます。これではACID の原子性(Atomicity)が崩れます。

この「全ノードを一斉に、全部成功か全部取消へそろえる」ための古典的合意プロトコルが 2相コミット(Two-Phase Commit, 2PC) です。1人の コーディネータ(調整役) が、複数の 参加者(各DBノード) の判断を取りまとめます。

prepare/commit の2フェーズ

名前のとおり、確定までを2段階に分けます。

フェーズ1: 準備(prepare / voting)

コーディネータが全参加者に prepare(投票要求)を送ります。各参加者は自分のローカル更新を実行し、コミット可能かを判断します。

  • 可能なら、更新内容と「コミットすると約束した」事実を永続ログに書いてから YES(vote-commit)を返す。
  • 制約違反やディスク不足などで無理なら NO(vote-abort)を返す。

ここが核心です。YES を返した参加者は、ロックを保持したまま自分ではもう結末を決められない「準備済み(prepared / in-doubt)」状態に入ります。あとはコーディネータの最終指示に従う義務を負います。

フェーズ2: 確定(commit / abort)

コーディネータは投票を集計します。

  • 全員 YES なら、自分の決定をログに書いてから全員に commit を送る。
  • 1人でも NO(または応答なし)なら、全員に abort を送る。

各参加者は指示どおりにローカルを確定し、ACK を返します。全 ACK が揃えばトランザクション完了です。

Coordinator                Participant A        Participant B
   |---- prepare ---------->|                    |
   |---- prepare ------------------------------->|
   |<--- YES ---------------|                    |
   |<--- YES -------------------------------------|
   | (全員YES → commit決定をログに記録)            |
   |---- commit ----------->|                    |
   |---- commit ------------------------------->|
   |<--- ACK ---------------|                    |
   |<--- ACK -------------------------------------|
“決定をログに書いてから送る”が肝

コーディネータが commit/abort の決定を自分のログに永続化してから指示を送るのは、途中で落ちても再起動後に同じ決定を再送(リカバリ)できるようにするためです。参加者側も prepare 時に YES の事実をログに残すので、再起動後にコーディネータへ「結末はどうなった?」と問い合わせ(in-doubt 解決)できます。ログを書く順序が、原子性の保証そのものです。

ブロッキング問題

2PC の最大の弱点がブロッキングです。フェーズ1で YES を返した直後、フェーズ2の指示が届く前にコーディネータが落ちると何が起きるか。

準備済みの参加者は、自分の判断ではコミットもアボートもできません(勝手にコミットすれば、他参加者がアボートしていたとき不整合になる)。だからロックを握ったまま、コーディネータの復帰をひたすら待つしかありません。この間、対象データは他のトランザクションから触れず、最悪システム全体が固まります。

参加者同士で勝手に決められない

「コーディネータが落ちたなら、生きている参加者だけで多数決すればいい」とはいきません。落ちた参加者がコーディネータからすでに commit を受け取っていた可能性があり、その事実を生存者は知りえないからです。結末を一意に決められる情報がコーディネータのログにしか無い――これがブロッキングの根本原因です。

2PC は、参加者・ネットワークが一時的に落ちても最終的に正しく合意できる(安全性は保つ)プロトコルですが、いつ合意できるかを保証できません。これは分散システムの不可能性(非同期環境で耐障害かつ常に合意できる手段は存在しない)とも整合する性質です。

3PC との違い

ブロッキングを緩和しようと、フェーズを1つ増やしたのが 3相コミット(Three-Phase Commit, 3PC) です。prepare と commit の間に pre-commit を挟みます。

観点2PC3PC
フェーズ数prepare → commit の2段階prepare → pre-commit → commit の3段階
コーディネータ障害時準備済み参加者が無期限にブロックしうるタイムアウトで参加者側が結末を推定し前進できる
pre-commit の意味なし“全員YESを確認済み”を全員に共有してから commit する
弱点ブロッキングネットワーク分断で誤った前進をしうる(安全性が崩れる)
往復回数・遅延少ない(速い)1段階分多い(遅い)

3PC の狙いは、「全員が YES だった」という事実を pre-commit で全参加者に行き渡らせてからコミットへ進む点にあります。これにより、コーディネータが落ちても、生存参加者は「pre-commit を受け取った=全員 YES だったはず」と推論し、タイムアウト後に自分たちで commit へ前進できます。結果としてブロッキングは減ります。

3PC が実務で主流にならない理由

3PC はノード故障(落ちたまま)を仮定すると前進できますが、ネットワーク分断(落ちていないのに通信が切れる)には弱いのが致命的です。分断された両側が「相手は死んだ」と誤認し、片方が commit、もう片方が abort へ進むと、安全性そのものが破れます。これはCAP 定理が指す、分断時に整合性か可用性かを迫られる構図そのものです。往復が増えて遅い割に保証が不安定なため、現場では採用例が限られます。

実務での落としどころ

完全な原子性を諦めずに可用性も欲しい場合、純粋な 2PC/3PC ではなく次が選ばれがちです。

  • Saga パターン: 大きな分散トランザクションを、各サービスのローカルトランザクションの連鎖に分解。失敗したら補償トランザクション(打ち消し処理)で巻き戻す。原子性は緩めるが、ロックを長く握らずブロッキングを避けられる。
  • 合意アルゴリズム(Paxos / Raft): コーディネータを単一障害点にせず、過半数の合意でコミット決定そのものを冗長化する。レプリケーションと組み合わせ、ノードが落ちても前進できる(レプリケーションとシャーディング参照)。
試験・面接での要点

「2PC がブロッキングするのは、prepare で YES を返した参加者が in-doubt 状態でコーディネータの決定待ちになり、その決定がコーディネータのログにしか無いから」――この因果を一息で言えるかが分かれ目です。3PC は pre-commit でブロッキングを緩和するがネットワーク分断に弱い、という対比もセットで押さえましょう。

2PC は「複数ノードを原子的にそろえる」という難題への素直な解答で、XA トランザクションや PostgreSQL の PREPARE TRANSACTION など今も広く実装されています。ただしブロッキングという代償は消えません。だからこそ、本当に厳密な原子性が要る所だけ 2PC を使い、それ以外は Saga や合意ベースへ倒す――この使い分けが、分散データ設計の勘所です。

データベース Article

2相コミット(2PC)と分散トランザクションを実務で読む

TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。

解決すること

2相コミット

比較で見る軸

難易度: advanced / カテゴリ: データベース / タグ数: 5

導入後に効く点

prepare で YES を返した参加者はコミットもアボートもできず待つしかないため、コーディネータ障害でロックを抱えたまま固まるブロッキング問題がある。

先に潰すリスク

用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。

数字・仕様の読み方
難易度
advanced
カテゴリ
データベース
タグ数
5

判断チェックリスト

  • 自社の用途が「2相コミット / 分散トランザクション」に近いか確認する。
  • 強みである「2PC はコーディネータが全参加者に prepare で投票を募り、全員 YES なら commit、1人でも NO なら abort して原子性をそろえる。」が本当に評価軸になるか確認する。
  • 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
  • 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
  • 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
  • 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。

次に確認する観点

2相コミット分散トランザクションコーディネータ整合性データベース2相コミット分散トランザクションコーディネータ
参考: 公式情報