分散トランザクション解説:2 Phase Commit vs Saga Pattern
Tony Duong
6月 2, 2026 ・ 1 分

Hello Interviewによる分散トランザクションのメモ — 1つのDBが複数になると何が変わるか、two-phase commit(2PC)がサービス間でほとんど使われない理由、業界がSagaを選ぶ理由。
トランザクションが簡単だった頃
初期は単一DBがすべてを処理。注文時:カード課金、在庫確保、会計仕訳 — すべて1トランザクション。失敗すればDBが自動ロールバック。
ここで重要なACID保証:
- 原子性 — 3つの書き込みがすべて成功するか、どれもしない
- 隔離性 — トランザクション中に途中状態を他のクエリが見ない
スケールアウトで変わること
トラフィックとデータが増える。DBをシャードするかマイクロサービス化 — 各サービスが独自のDBを持つ。
1トランザクションだった決済フローが3つの独立DBへの別々の操作になる:
- カード課金(決済DB)
- 在庫確保(在庫DB)
- 仕訳記録(会計DB)
独立DB間にトランザクションを張れない。課金がコミットした後に在庫確保が失敗しても、DBレベルのロールバックはない。
これが分散トランザクション:複数の独立DB/サービスにまたがる1つの論理操作で、すべて成功するかクリーンアップが必要。
Two-phase commit(2PC)
古典的な学術的解。コーディネータが全参加者の合意を確認してから確定させる。
Phase 1 — Prepare
各参加者に「コミットできるか?」と聞く。各DBが作業し、変更を永続化し、行をロックし、yes/noで投票。
- no が1つでも → 全員abort
- 全員yes → Phase 2へ
Phase 2 — Commit
全員にcommitを送信。参加者が変更を確定しロック解除。
利点: 強い一貫性 — 単一DBと同じ保証。
2PCが本番で失敗する理由
2PCはブロッキングプロトコル — 複数マシンが同時に健全であることに依存するため危険。
コーディネータクラッシュ: 全yesを集めた後、commit送信前にクラッシュ。参加者はロックを保持したまま動けない。それらの行に触れるトランザクションがすべてブロック。
業界の現実: 独立サービス間で2PCを使う者はほぼいない。Pat HellandのLife Beyond Distributed Transactionsは、自律サービス間の分散トランザクションはインターネット規模では機能しないと論じる。
2PCは分散DB内部(Google Spanner、YugabyteDB)では使われる — コーディネータと参加者が密結合。独立サービス間では破綻する。
Sagaパターン
Uber、Netflix、Amazon、DoorDashが本番で使うもの。
別の前提: サービス間のall-or-nothing原子性は不要。最終的に一貫した状態に到達できればよい。
- 独立したローカルトランザクションの連鎖に分割
- 各サービスが独自のDBにコミット
- 後続ステップ失敗時は補償アクション(ビジネスレベルの取り消し)
トレードオフ: 結果整合性。補償中は一時的に不整合(課金のあと返金が見える)が、他のトランザクションはブロックされない。
コレオグラフィ vs オーケストレーション
コレオグラフィ(分散)
各サービスが完了時にイベントを発行。他が反応。
2–3ステップの単純フロー向き。5–6サービスでは状態追跡が困難。
オーケストレーション(集中)
オーケストレータがステップごとに制御。失敗時に補償の順序を把握。
ツール:Temporal、AWS Step Functions。
2PCコーディネータとの違い: オーケストレータは耐久。クラッシュ後、DBから状態を読み再開 — ダングリングロックなし。
大規模チームの多くはオーケストレーションを使う。
補償アクション — 難しい部分
- 返金は顧客に可視
- 取り消せない操作:送信済みメール、第三者webhook
- 補償も失敗する → リトライ、冪等が必須
デュアルライト問題とトランザクションアウトボックス
DB保存とイベント公開は別システムへの2書き込み。
修正:トランザクションアウトボックス
- データとイベントを同一DBの1ローカルトランザクションで書く(
outboxテーブル) - バックグラウンドプロセス(CDCまたはポーリング)がブローカーへ公開
意思決定フレームワーク
まず:分散トランザクションは本当に必要か?
一緒にトランザクションするデータを同一DBに置けるならそうする。ローカルACIDが最善。
どうしても分散が必要なら
Saga — 業界のデフォルト。
| 状況 | 選択 |
|---|---|
| 3–4ステップ、中央可視性不要 | コレオグラフィ |
| 複雑フロー、補償が難しい | オーケストレーション |
| 結果整合性が不可 | 単一分散DB(Spanner等)— サービス間DIY 2PCではない |
本番パターン
オーケストレーションSaga + 各ステップの冪等性 + トランザクションアウトボックス。
要点
- サービスごとにDBを分けると単一DBのACIDは崩れる
- 2PCは強い一貫性だがブロックする
- Sagaはローカルコミット + 補償
- トランザクションアウトボックスでデュアルライトを回避
- 可能なら:トランザクションを分散しない
🌐 Claudeによる翻訳