🎓 レベル:標準 | 重要度:A(必須)
📎 前提:合意問題とFLP不可能性 | 関連:Raft・分散トランザクションとSaga
要点(BLUF)
- 2相コミット(2PC)は、複数ノードにまたがるトランザクションを「全員commit か 全員abort」に揃えるアトミックコミットプロトコル。調整役(コーディネータ)が準備→コミットの2フェーズで仕切る。
- 2PCの致命的弱点はブロッキング:参加者が「準備OK(commit可)」を返した後にコーディネータが落ちると、参加者はcommitともabortとも決められず固まる。
- 3相コミット(3PC)は中間フェーズを足して非ブロッキングを狙うが、ネットワーク分断には弱い。現代はコーディネータ自体を合意(Raft)で冗長化して2PCのブロッキングを実質回避する。
問題設定 ── 全員一致でコミットしたい
銀行Aから引き、銀行Bへ足す。片方だけコミットされたら不整合。全ノードが同じ結末(commit/abort)に至ることが要る。これは合意問題(合意問題とFLP不可能性)の一種で、特に「全員賛成でなければabort」という強い条件付きです。
アルゴリズム ── 2PC の2フェーズ
sequenceDiagram
participant C as コーディネータ
participant P1 as 参加者1
participant P2 as 参加者2
Note over C,P2: フェーズ1: 準備(投票)
C->>P1: prepare
C->>P2: prepare
P1-->>C: yes(commit可・ログ書込)
P2-->>C: yes
Note over C,P2: フェーズ2: 決定
C->>P1: commit
C->>P2: commit
P1-->>C: ack
P2-->>C: ack
- フェーズ1(準備):コーディネータが prepare を送り、各参加者は「commitできるか」を判断し、yesなら自分をロックして永続ログに記録してyesを返す(以後abortできない準備完了状態)。
- フェーズ2(決定):全員yesなら commit、1つでもnoなら abort を全員へ。
正しさの観点 ── 安全性は守るが活性が弱い
- 安全性(原子性):全員commitか全員abort。これは2PCでも守られる。
- 活性(ブロッキング問題):参加者がyesを返した後にコーディネータがクラッシュすると、参加者は結末を知らずにロックを握ったまま無期限に待つ。他の参加者にも聞けない(コーディネータだけが全体の票を知っている)。
flowchart LR
Y["参加者:yesを返した(commit可・ロック中)"] --> D["コーディネータがクラッシュ"]
D --> B["commit? abort? 不明 -> 永久ブロック"]
これは 合意問題とFLP不可能性 の「遅いと死んだが区別できない」が、ロック保持という形で牙を剥いた例です。
3PC ── 非ブロッキングの狙いと限界
3PCは準備とコミットの間に pre-commit フェーズを挟みます。「全員yes」を全員が知ってからコミットに進むので、コーディネータ故障時も参加者だけで結末を推論でき、ブロッキングを避けられます。ただし——ネットワーク分断が起きると、分断された両側が別々の結末(片方commit・片方abort)に進む危険があり、安全性を破りうる。さらにメッセージ往復が増えて遅い。このため実用では3PCはあまり使われません。
他手法との比較 ── 現代の解
| 方式 | ブロッキング | 分断耐性 | 実用 |
|---|---|---|---|
| 2PC | する | — | 単一コーディネータ前提なら今も広く使われる |
| 3PC | しにくい | 弱い | ほぼ使われない |
| 2PC + コーディネータをRaft化 | 実質しない | 強い | 現代の定番(Spanner等) |
| Saga(分散トランザクションとSaga) | しない(補償で巻き戻し) | 強い | マイクロサービス向き |
要するに「2PCのブロッキングはコーディネータが単一障害点だから」。コーディネータを合意(Raft)でレプリケーションすれば、落ちても別のコーディネータが結末を引き継げ、ブロッキングが消えます。
なぜ分散だと難しいか(直観)
「全員一致でコミット」は、一人でも音信不通になると進めない。準備完了後はもう引き返せない(ロック中)ので、コーディネータの沈黙が全員を人質にする。強い一貫を全ノードで保つ代償が、この脆さです。
⚠️ よくある誤解・落とし穴
- 「2PCは合意だから分断に強い」→ 逆。コーディネータ単一障害点でブロッキングする。素の2PCはCAPのC側で可用性が低い。
- 「3PCにすれば安全に非ブロッキング」→ 分断時に安全性を破りうる。万能ではない。
- 「prepareでyesを返したら後で気が変われる」→ 不可。yesはコミット義務の宣言(永続ログに記録)。
- 「2PCはもう古い」→ コーディネータをRaft化した2PCは現役。Sagaと使い分ける。
対応ラボ
なし(概念回)。コーディネータ冗長化の核となるリーダー合意は Raft のラボで実証します。
関連
- 不可能性の背景は 合意問題とFLP不可能性
- コーディネータ冗長化の合意は Raft
- 巻き戻しで解く代替が 分散トランザクションとSaga