🎓 レベル:発展 | 重要度:A(必須)
📎 前提:2相コミット・3相コミット | 関連:冪等性と再試行・バックオフ・パーティショニング/シャーディング
要点(BLUF)
- 分散トランザクション=複数のサービス/DB/パーティションにまたがる更新を、全体として整合させる仕組み。古典は2PC(2相コミット・3相コミット)だがブロッキングと密結合が難点。
- Sagaは、長いトランザクションをローカルトランザクションの列に分解し、途中で失敗したら**補償トランザクション(逆操作)**で前のステップを打ち消す方式。マイクロサービス向きの定番。
- 代償は原子性と分離性を諦めること:Sagaは「全部成功 or 全部補償」を保証するが、途中経過が外部から見える(他者が中間状態を観測しうる)。これを設計で受け止める。
問題設定 ── サービスをまたいで一貫させたい
注文=「在庫を引く」「決済する」「配送を手配する」が別サービス(別DB、パーティショニング/シャーディング)にある。1つが失敗したら全体を取り消したい。だが2PCは全サービスをロックし、コーディネータ障害でブロックする(2相コミット・3相コミット)。マイクロサービスでは2PCの密結合・低可用性が嫌われます。
アルゴリズム ── Saga と補償
Sagaは各ステップを即コミットするローカルトランザクション T1…Tn に分け、各 Ti に補償 Ci(Ti を打ち消す逆操作)を用意します。失敗したら、それまでのステップを逆順に補償します。
sequenceDiagram
participant O as 注文Saga
participant I as 在庫
participant P as 決済
participant D as 配送
O->>I: T1 在庫を引く(コミット)
O->>P: T2 決済する(コミット)
O->>D: T3 配送手配 -> 失敗!
Note over O: 逆順に補償を実行
O->>P: C2 返金(T2を打ち消す)
O->>I: C1 在庫を戻す(T1を打ち消す)
実装は2系統:
- コレオグラフィ(choreography):各サービスがイベントを発行し合い、次のステップを自律的に進める(中央調整なし、疎結合だが全体像が見えにくい)。
- オーケストレーション(orchestration):中央のSagaオーケストレータが手順を指揮する(見通しが良いが調整役が要る)。
正しさの観点 ── 何を保証し、何を諦めるか
- 原子性(実質):「全 Ti 成功」か「失敗ステップまでの補償完了」のどちらかに収束。結果整合的な原子性。
- 諦める分離性(isolation):T1 コミット後・補償前の中間状態が外から見える。たとえば「在庫を引いた直後・返金前」に他者がその在庫数を読む。対策:セマンティックロック(“処理中”フラグ)、可換な操作設計、再読時の確認。
- 補償の冪等性が必須:補償も失敗・再試行されうるので、Ci は何回実行しても同じ結果でなければならない(冪等性と再試行・バックオフ)。補償が”逆操作として正しいか”も非自明(メール送信は取り消せない=補償は”訂正メール”になる)。
他手法との比較
| 方式 | 原子性 | 分離性 | 結合度/可用性 | 向く場面 |
|---|---|---|---|---|
| 2PC(2相コミット・3相コミット) | 強い | 強い | 密結合・低可用(ブロッキング) | 単一DB内・強整合必須 |
| 2PC+Raft化 | 強い | 強い | 中・高可用 | 強整合の分散DB(Spanner) |
| Saga | 結果整合的 | 弱い(中間見える) | 疎結合・高可用 | マイクロサービス・長時間処理 |
なぜ分散だと難しいか(直観)
単一DBのトランザクションは ACID を無料でくれるが、サービス境界を越えた瞬間に原子性・分離性が高くつく。Sagaは「完全な原子性を諦め、補償で”だいたい元に戻す”」現実解。だが「元に戻せない操作(送信済みメール・出荷済み荷物)」があるので、補償は逆操作ではなく訂正アクションになる——ここに業務設計の難しさが宿ります。
⚠️ よくある誤解・落とし穴
- 「SagaはACIDの代替」→ 違う。原子性は近似、分離性は犠牲。中間状態が見える前提で業務を設計する。
- 「補償すれば完全に元通り」→ 取り消せない副作用(通知・課金確定)は逆操作にならない。訂正で対応。
- 「補償は1回だけ実行される」→ 補償も再試行されうる。冪等でないと二重返金等が起きる(冪等性と再試行・バックオフ)。
- 「コレオグラフィが常に良い」→ サービスが増えるとイベントの連鎖が追えなくなる。複雑ならオーケストレーションで見通しを確保。
対応ラボ
なし(概念回)。補償の前提となる冪等な再試行は 冪等性と再試行・バックオフ のラボで実証します。
関連
- 強整合版の原子コミットは 2相コミット・3相コミット
- 補償・再試行の信頼性は 冪等性と再試行・バックオフ
- サービス分割の前提は パーティショニング/シャーディング