Sagaパターンとは?補償トランザクション設計と実装方式の選び方を解説【2026年版】
Sagaパターンは、複数のサービスにまたがる処理を、それぞれのデータベースで完結する小さなトランザクションの連鎖に分解し、途中で失敗したら打ち消し処理を逆順に走らせて整合性を取り戻す設計です。2相コミットのようにロックを跨がせない代わりに、失敗の後始末をアプリケーション側で書く責任が生まれます。この記事では、補償トランザクションの書き方、コレオグラフィとオーケストレーションの選択条件、分離性が失われて起きるデータ異常への対策、AWS Step FunctionsやTemporalなど実装基盤の比較、そして採用する業務と見送る業務の線引きまでを実装者の視点で整理します。
まとめ|Sagaパターンを採用する業務と2相コミットで済ませる場面の判断軸
結論から書きます。Sagaパターンは分散システムの標準装備ではなく、「サービスごとにデータベースが分かれ、1つの業務が複数サービスをまたぐ」条件が揃った箇所だけに部分適用する道具です。受注から在庫引当・与信確認・配送手配へ進む注文フロー、航空券と宿泊をまとめて押さえる予約フロー。この種の業務では、どこかが失敗したときに前の工程を打ち消す処理が業務要件として最初から存在します。
逆に、同一データベース内で完結する処理にSagaを持ち込む理由はありません。サービスが分かれていても、参加するのが2つでロック時間が数十ミリ秒に収まるなら、2相コミット対応のミドルウェアで済ませたほうが実装量もテスト量も小さくなります。
採用後の難易度は3点で決まります。補償処理を業務として定義できるか、重複配信に対して冪等に作れるか、補償そのものが失敗したときの逃がし先を用意できるか。以降の章で、この順に実装手順まで落として説明します。
Sagaパターンの基本構造|ローカルトランザクション連鎖と補償トランザクションの役割
まず押さえるのは、Sagaが「1つの大きなトランザクション」を作る技術ではない点です。サービスごとにデータベースを分ける設計の背景はマイクロサービスとモノリスの違いと選び方で整理しているため、ここでは分割済みの前提で整合性の取り方だけを扱います。
2相コミットとの違い|ロック保持時間とサービス間結合という2つの制約
2相コミットは、調整役が全参加者に準備を問い合わせ、全員が同意してから一斉にコミットします。原子性は保たれる一方、準備から確定までの間、各参加者は行ロックを握り続けます。1つでも応答しなければ、他の参加者はロックを抱えたまま待機する構造です。単一データベース内のACIDや分離レベルの詳細はトランザクションのACIDと分離レベルの解説を参照してください。
Sagaは、この待機を最初から捨てます。各サービスは自分のデータベースへ書いた時点で即座にコミットし、次のサービスへイベントかコマンドを渡す。ロックはローカルトランザクションの間だけで解放されるため、参加サービスが5つに増えても待ち時間は積み上がりません。代わりに、途中で失敗したときのロールバックが効かなくなります。
補償可能・ピボット・再試行可能|Sagaを構成する3種のトランザクション区分
Microsoft の Azure Architecture Center(2026年7月25日更新版)は、Sagaの各ステップを3種類に分類しています。この分類が、後の実装方針をそのまま決めます。
- 補償可能なトランザクション:後から打ち消し処理を実行できるステップ。在庫の引当、与信枠の仮押さえなど
- ピボットトランザクション:後戻りできない境界。越えたら前工程の打ち消しは意味を失う。決済の確定、外部への発注送信など
- 再試行可能なトランザクション:ピボット以降のステップ。打ち消さず成功まで再試行する。通知メール送信、配送ラベル発行など
設計時にやることは単純です。業務フローを並べ、どこがピボットかを1点だけ決める。その手前は補償可能に、後ろは冪等な再試行可能に作ります。ピボットが2箇所あるように見えるなら、Sagaを2本に分けるべき兆候です。
補償トランザクションの書き方|取り消しではなく打ち消し操作を定義する設計
補償トランザクションは、データベースのロールバックとは別物です。すでに公開された状態を「なかったこと」にはできないため、逆向きの業務操作を新しく1件記録します。在庫を3個引き当てたなら引当解放を3個分、与信枠を5万円確保したなら解放を5万円分記録する。履歴には両方が残ります。
ここで頻出する失敗が、打ち消せない操作を補償可能なステップに置いてしまう設計です。送信済みのメール、外部決済ゲートウェイへ通した売上確定、取引先システムへ渡した発注データ。これらは打ち消しの業務手順が存在しないか、存在しても人の承認を伴います。「この操作の逆向き操作を業務担当者が説明できるか」を設計段階で確認し、説明できないものはピボット以降へ移してください。記録の持ち方そのものはイベントソーシングによる状態再生とイベントストア設計で扱っています。
コレオグラフィとオーケストレーション|2方式の適用条件と切り替えの判断基準
Sagaの実装方式は2つです。中央の調整役を置かずイベント交換だけで進めるコレオグラフィと、専任の調整役が各サービスへ指示を出すオーケストレーション。どちらが優れているという話ではなく、フローの複雑さで機械的に決まります。
コレオグラフィの適用条件|参加サービス3つ以下・分岐なしという線引き
コレオグラフィでは、各サービスがローカルトランザクション完了時にドメインイベントを発行し、購読した次のサービスが動きます。調整役のコードを書かずに済むため、初期実装は最短です。単一障害点も生まれません。
採用の線引きは、参加サービス3つ以下かつ条件分岐なしです。4つ目が入った時点で「どのサービスがどのイベントに反応するか」を追跡できるのはコードを書いた本人だけになり、半年後の改修で事故が起きます。Azure Architecture Center も欠点として、ステップ追加時の混乱・参加者間の循環依存・全サービスを起動しないと組めない統合テストの3点を挙げました。
オーケストレーションの適用条件|分岐と並行実行を持つ業務フローでの選択
オーケストレーションは、調整役が各ステップの状態を保持し、次に何を呼ぶかを判断します。フローが1箇所にあるため、条件分岐も並行実行も表現できます。「与信がNGなら在庫引当をスキップして補償へ」といった業務ルールを1ファイルで読めるのが最大の利点です。
欠点は調整役が障害点になること、そして調整ロジックの実装量が増えることです。前者はマネージドサービスに寄せれば大半が解消します。参加サービスが4つ以上あるならオーケストレーション一択で構いません。コレオグラフィで書き始めて後から調整役を入れる移行は、初期の設計時間を節約した分を上回るコストがかかります。
2方式の比較表|変更容易性・テスト容易性・障害切り分けコストの3観点
選定会議で使う観点は次の3つに絞ります。実装量そのものではなく、運用に入ってからの負荷で比べてください。
| 観点 | コレオグラフィ | オーケストレーション |
|---|---|---|
| ステップ追加 | 購読関係の再設計が必要 | 定義1箇所の変更で済む |
| 単体テスト | サービス単位で書ける | 調整役のモックが要る |
| 統合テスト | 全サービス起動が前提 | 調整役の実行履歴で追える |
| 障害切り分け | ログ横断で追跡する | 実行履歴を1画面で確認 |
| 単一障害点 | なし | 調整役に集中する |
| 向くフロー | 直線・3サービス以下 | 分岐あり・4サービス以上 |
実務で効くのは障害切り分けの行です。深夜に「注文が途中で止まっている」と連絡が来たとき、コレオグラフィでは各サービスのログを時刻で突き合わせる作業から始まります。オーケストレーションなら、実行履歴を開けばどのステップで止まったかが1画面で分かります。
分離性の欠如が生むデータ異常|ダーティリードと更新喪失への6つの対策
Sagaで最も見落とされるのがこの章の話です。各ステップが即座にコミットするということは、Saga完了前の中間状態が他のトランザクションから見えることを意味します。
Sagaが満たす保証はACD|分離性が失われることで起きる3種の異常
SagaはACIDのうち原子性・一貫性・持続性は満たしますが、分離性(Isolation)は満たしません。Azure Architecture Center はこの状態で起きる異常として、更新喪失・ダーティリード・あいまい読み取りの3つを挙げています。
具体例で言えば、注文Aが在庫を引き当てた直後、Saga完了前の在庫数を注文Bが読み取り、その後に注文Aが補償で引当を解放する。注文Bは存在しない不足状態を根拠に判断を下したことになります。これが「原因不明の数字のずれ」として現れます。
セマンティックロックと再読み取り|実務で先に入れる2つの対策の実装手順
対策は6種類が知られています。セマンティックロック、可換更新、悲観的ビュー、再読み取り値、バージョンファイル、値に基づく同時実行制御。6つ全部を入れる案件はまず無く、実務では次の2つから始めます。
- セマンティックロック:レコードに「処理中」を表す状態列を持たせ、Saga開始時に立てて完了または補償時に下ろす。他のSagaはこの列を見て待機する
- 再読み取り値:更新の直前に対象行を読み直し、Saga開始時点から変わっていれば処理を中断して補償へ回す。楽観ロックのバージョン列で判定する
優先度は明確です。中間状態が業務判断に使われる可能性があるなら、まずセマンティックロックを入れてください。在庫引当中・与信確認中といった状態を明示するだけで、ダーティリードの大半は消えます。再読み取り値は、同一レコードへの同時更新が観測されてから足せば間に合う対策です。可換更新やバージョンファイルは効く場面が限られるため、最初から検討対象に入れる必要はありません。
Sagaの実装基盤|マネージド型と自前実装のコストと運用負荷の比較
オーケストレーションを選んだ場合、調整役をどこに置くかで運用負荷が変わります。選択肢はマネージドのワークフローサービス、コードで書くワークフローエンジン、自前実装の3つです。
AWS Step Functionsでの実装|状態遷移とCatch句による補償の呼び出し
AWS の規範ガイダンスは、Step Functions のステートマシンでSagaを組む手順を公開しています。各業務ステップをタスク状態として定義し、失敗時の遷移先を Catch 句で補償用の状態へ向ける。これだけで、状態の永続化・指数バックオフによる再試行・実行履歴の可視化がサービス側の機能として付いてきます。
実装上の注意は2点です。ステートマシン定義に業務ロジックを書き込みすぎるとテストしづらくなるため、判断は各サービス側に残し、定義には遷移だけを書く。もう1点は Standard ワークフローと Express ワークフローの選択で、実行履歴が残り長時間実行に耐えるのは Standard 側です。数分以上かかる業務Sagaでは Standard を選びます。
TemporalとAxon Framework|コードでSagaを書く基盤の版と特性
クラウドサービスに寄せずコードで書く選択肢もあります。Temporal は 2026年8月5日時点で 1.31 系が公開されており、ワークフローを通常の関数として書きながら、状態の永続化と再開をエンジン側が担う構造です。Java 圏では Axon Framework が 5.2 系(同時点)で、イベント駆動の基盤とSaga管理を同一フレームワークで扱えます。
この2つが向くのは、分岐が複雑でステートマシン定義では表現しきれない場合、または特定クラウドへの依存を避けたい場合です。引き換えに、エンジン自体の運用(クラスタ構成・版upgrade・保持期間の設計)が自チームの担当になります。Axon の詳細はAxon Frameworkの構成と特徴の解説にまとめています。
自前実装の判断基準|状態テーブルとリトライ機構を自作するときの工数感
自前実装は、Sagaの実行状態を保持するテーブルを作り、失敗時に補償を逆順で呼ぶスケジューラを書く構成です。書くべきものは、状態テーブル、遷移の記録、再試行の制御、重複起動の防止、監視用の一覧画面。この5点セットになります。
判断基準を1つだけ挙げるなら、Sagaが1種類で参加サービスが3つ以下、かつ既にジョブ実行基盤を持っているなら自前で構いません。3種類を超える見込みがあるなら、その時点で基盤を導入してください。自前実装の工数は最初のSagaでは小さく見えますが、2本目・3本目で再試行と監視の作り込みが効いてきて逆転します。
実装で詰まる3論点|冪等性・タイムアウト・補償失敗への具体的な対処
設計が正しくても、この3つの手当てが抜けていると本番で必ず不整合が出ます。順に押さえてください。
冪等性の担保|Sagaインスタンス識別子と処理済みテーブルによる重複排除
メッセージ基盤は、多くが少なくとも1回の配信を保証する方式です。つまり同じメッセージが2回届きます。在庫引当が2回走れば在庫は二重に減ります。
実装は単純です。Saga開始時に一意な識別子を発行し、全ステップのメッセージに載せる。各サービスは「識別子とステップ名の組を処理済みか」を専用テーブルで判定し、処理済みなら何もせず成功を返します。判定と業務処理は同一のローカルトランザクションに入れてください。別々にすると、判定だけ済んで処理前に落ちたときに永久に処理されない状態が生まれます。補償側も同じ扱いが必要です。
タイムアウト設計|応答なしを失敗と見なすまでの待ち時間と再試行回数
応答が返らないサービスを、いつ失敗と判定するか。ここを決めないと、Sagaが未完了のまま滞留し続けます。設定はステップ単位とSaga全体の2段階で、全体のほうは業務が許容できる待ち時間から逆算します。予約確定なら数分、バッチ寄りの発注なら数時間が現実的な範囲です。
再試行は指数バックオフで3回程度に留め、超えたら補償へ倒します。無限再試行は、相手サービスが落ちている間に負荷を掛け続ける挙動です。呼び出し先の障害連鎖を止める仕組みはサーキットブレーカーによる障害連鎖の遮断で扱っており、Sagaのステップ呼び出しと組み合わせる構成が実務的です。
補償が失敗したときの扱い|手動介入キューと監視アラートの設計指針
補償トランザクションも失敗します。相手サービスの停止、打ち消し対象レコードの別処理による変更といった理由です。自動で解決しようとせず、人が介入する経路を最初から用意してください。
具体的には、補償の再試行が上限に達したSagaを「要手動対応」の状態で保存し、専用の一覧に出す。同時に運用チームへアラートを飛ばし、対象の識別子・止まったステップ・補償が必要な残作業を本文に含めます。この一覧が空であることを日次で確認する運用まで、初期リリースの範囲に入れてください。後から足そうとすると、不整合が発生してから作ることになり、調査に人手を取られて手が回りません。
Sagaを見送る条件|単一DBで足りる業務と補償を書けない外部連携の線引き
ここは言い切ります。Sagaを入れないほうがよい場面は明確に存在し、判断を先送りするとコード量だけが増えます。
見送るべき3条件|単一DB・補償不能な副作用・整合性を待てない業務
次のいずれかに当てはまるなら、Sagaは採用しないでください。
- 関係するデータが同一データベースに収まっている:分けたい理由が組織都合だけなら、まずモジュール分割で足りる
- 打ち消し操作を業務として定義できない副作用がある:外部への確定送信や第三者への通知が中盤に入るフローは、確定を最後尾のピボットへ移す設計に組み替える
- 秒未満で全体整合性が必要:Sagaは結果整合性の設計で、完了までの数百ミリ秒から数秒は中間状態が見える。高頻度な残高更新では単一DBの強い整合性を選ぶ
3つ目は対策で緩和できると考えて突き進む例が絶えません。セマンティックロックを入れれば中間状態は隠せますが、隠している間は他の処理が待つため、2相コミットと同じ待ち時間が別の形で戻ってきます。
失敗パターン|全業務にSagaを敷いて補償コードが本体を上回る設計崩れ
典型的な崩れ方を1つ挙げます。マイクロサービス化の方針と一緒に「サービスをまたぐ処理は全てSagaで」と決めてしまう進め方です。参照系や単純な2サービス連携にまで敷くと、補償と冪等性処理の実装量が業務ロジック本体を上回ります。
補償コードは業務価値を生まない一方、業務ルールが変わるたびに追随が必要です。在庫引当のルールが変われば引当解放も変える。その二重保守が全業務に掛かれば、機能追加の速度は半減します。Sagaを敷く箇所は「失敗時の打ち消しが業務要件として元々存在するフロー」に限定し、それ以外は失敗をそのまま利用者へ返して再操作してもらう設計のほうが、総保守コストは小さく収まります。
受託開発での進め方|段階導入の手順とテスト・監視で押さえる観点
既存システムへ後からSagaを入れる場合、全体設計から始めると合意形成だけで数か月かかります。1本を通しで作り切る進め方を採ってください。
段階導入の手順|1業務フローに絞って補償を含めて作り切る進め方
- 打ち消しが業務要件として既に存在するフローを1本選ぶ(注文キャンセル、予約取消など)
- ステップを並べ、ピボットを1点だけ決める。手前を補償可能、後ろを再試行可能に振り分ける
- 補償の業務手順を、開発者ではなく業務担当者に確認する。説明できない打ち消しは設計を組み替える
- 参加サービスが4つ以上ならオーケストレーション基盤、3つ以下なら自前の状態テーブルで始める
- 冪等性・タイムアウト・手動介入キューを同じリリースに含める
この1本が本番で3か月動いてから、2本目の対象を選びます。想定外として多いのは、補償の失敗頻度が事前見積もりより高いことと、業務側が中間状態の可視化を求めることの2点です。
テストと監視の設計|補償経路を落として確かめる検証と相関IDの付与
テストで最も抜けやすいのが補償経路です。正常系は結合テストで自然に通りますが、補償は意図的に失敗を注入しないと1度も実行されないままリリースされます。各ステップを個別に失敗させるテストケースを、ステップ数だけ用意してください。
監視側は、Saga識別子を相関IDとして全サービスのログへ出力する設定から始めます。障害時の調査時間は、これがあるかどうかで桁単位に変わる部分です。未完了Sagaの滞留件数と補償の発生率を常時計測し、補償率が普段の水準を超えたら上流の異常を疑う運用にしてください。マイクロサービス全体の監視指標の組み方はREDメソッドによる3指標の監視設計にまとめています。
サービス間の連携設計を外部と組んで進める場合は、API開発・システム連携で、既存システムを止めずに一部のフローだけをSagaへ寄せる進め方の相談を受け付けています。補償処理の業務定義とテスト設計まで含めて請け負う形が多い領域です。
よくある質問
Sagaパターンの検討でよく挙がる質問を、実装判断の観点でまとめます。
Sagaパターンと2相コミットはどちらを選ぶべきですか?
参加サービスが2つで、全員が同じトランザクションマネージャに対応しており、ロック保持が短時間で済むなら2相コミットが簡潔です。それ以外はSagaを選びます。判断の分かれ目は参加者数ではなく、ロックを握ったまま待てる時間の長さです。外部APIやメール送信のように応答時間が読めない処理が1つでも混ざるなら、2相コミットは選択肢から外れます。
補償トランザクションが失敗した場合どうなりますか?
自動では解決せず、データは不整合な中間状態のまま残ります。設計としては、補償を指数バックオフで数回再試行し、それでも失敗したら「要手動対応」の状態で保存して運用チームへ通知する経路を用意します。自動復旧で作り込もうとすると、復旧処理自体が失敗したときの復旧処理が必要になり終わりません。人が介入する前提の逃がし先を置くほうが、運用は安定します。
コレオグラフィとオーケストレーションはどう使い分けますか?
参加サービス3つ以下かつ条件分岐なしならコレオグラフィ、4つ以上または分岐や並行実行があるならオーケストレーションという線引きで判断できます。迷う規模ならオーケストレーションを選んでください。理由は障害時の調査コストです。後からの移行はイベント購読の依存関係をほどく大工事になるため、初期選択の影響が長く残ります。
SagaパターンとCQRSやイベントソーシングの関係は何ですか?
別々の設計で、必須の組み合わせではありません。Sagaはサービスをまたぐ整合性を扱い、CQRSは読み書きのモデルを分け、イベントソーシングは状態を出来事の列として保存します。実務で併用が多いのは、コレオグラフィ型のSagaがドメインイベントを前提とし、イベントを一級市民として扱う基盤と噛み合うからです。ただしSagaだけの導入も可能で、既存の上書き保存のデータベースに状態テーブルを1本足せば成立します。
Sagaパターンの実装にはどのくらいの工数がかかりますか?
参加サービス3つの直線フロー1本で、補償・冪等性・タイムアウト・手動介入キューまで含めると、既存のサービス実装がある前提でも数週間規模になります。内訳で大きいのは業務側との補償手順の確認と、ステップ数だけ必要になる失敗注入テストの2つです。マネージドのワークフローサービスを使えば状態管理と再試行の実装は削れますが、この2つは基盤を変えても残ります。見積もりでは、正常系の実装量と同程度を補償と検証に見込んでください。
関連記事
- CQRS(コマンドクエリ責務分離)とは:Sagaと併用されることの多い読み書き分離の設計を扱っています
- イベント駆動アーキテクチャとは:コレオグラフィ型Sagaの前提になるイベント連携の全体像です
- AsyncAPIとは(3.0仕様と設計):Sagaで交換するイベントの契約を仕様として管理する方法です
- トランザクションとは(ACIDと分離レベル):Sagaが捨てる分離性の元になる単一DBの保証を確認できます
- REDメソッドとは(監視の3指標):未完了Sagaの滞留を検知する監視指標の設計に使えます