前置き
サーガにおける状態管理
分散トランザクション(Sagaパターンなど)において、オーケストレーターはプロセス全体の「状態」を一元的に管理する役割を果たします。
「分散トランザクションの各イベントがいまどのような状態なのか?」
「どこでエラーが発生したのか?」
「いまどこまで補償トランザクションが実行されているのか?」という状態ログを
一元管理しているのが、オーケストレーション型のサーガの特徴です。
オーケストレーターが持つ「状態ログ」の具体例
オーケストレーターは、以下のような情報を状態として永続化(データベースや専用のストレージに保存)しています。
・トランザクション全体のIDと現在のステータス(例: 実行中, 完了, 失敗)
・各ステップ(ローカルトランザクション)の実行状態(例: 在庫確保サービス呼び出し済み、支払い処理成功、配送手配失敗)
・どこでエラーが発生したか、そのエラー内容やリトライ回数
・どこまで補償トランザクションが実行されたか(例: 支払い処理は成功したが配送手配で失敗したため、支払いの取り消し処理を実行済み)
なぜ状態を持つことが重要なのか?
この「状態」を持つことにより、オーケストレーターは以下を実現します。
プロセスの可観測性(Observability)
「ID:123の注文は、今どの段階にあるのか?」という問いに即座に答えることができます。
これは監視やトラブルシューティングにおいて非常に重要です。
信頼性の高いエラー回復
途中のステップでシステムがクラッシュしても、オーケストレーターは保存された状態を読み込むことで、
「支払い処理の途中から再開する」
「配送手配で失敗したから、支払いと在庫確保の補償トランザクションを実行する」
といった判断を正確に行えます。
これが、
コレオグラフィ型よりも、オーケストレーション型の方が回復性が高い
という特徴の理由です。
ステートマシンとしてのオーケストレーター
オーケストレーターは、分散トランザクション全体のステートマシンとして機能します。
以下の図のように、正常系のフロー(実践)と、エラー発生時の補償フロー(点線)を定義し、現在の状態を常に追跡します。
図中で、補償トランザクションの失敗の部分(赤ひし形の失敗ケース)は、
端折らせてもらいました。
この「状態」を一箇所で集中管理するのがオーケストレーション方式であり、
各サービスが自律的にイベントを捌いていくコレオグラフィ方式との最大の違い
となります。
代表的なSagaの責務割り当てパターン
過去の記事でも触れましたが、分散トランザクションを実現するSagaパターンにおいて、
その実行責務をどのように割り当てるかにはいくつかの代表的なパターンがあります。
大きく分けて、オーケストレーション・ベースとコレオグラフィ・ベースの2種類に分類でき、オーケストレーションの中にもバリエーションが存在します。
パターン1:専任オーケストレーター・サービス
エピックサーガ、おとぎ話サーガ、パラレルサーガなどがこれに該当します。
プロセス全体を管理・実行するためだけの、新しい「オーケストレーター」というサービスを専任で用意する方式です。
特徴
・オーケストレーターは、サーガのワークフロー(どの順番で、どのサービスを呼び、エラー時に何をするか)を定義・実行することが唯一の責務です。
・オーケストレーター自身はビジネスロジックを持ちません。
・オーケストレーターの持つステートモデルのDBに、サーガの現在の状態(どこまで進んだか、失敗したか)を一元的に管理・永続化しています。
メリット
✅ 関心の分離
Sagaの管理ロジックと、各サービスのビジネスロジックを明確に分離できる。
各種サービスを担当するチームは、調整を気にする必要がないため、認知負荷の軽減にも繋がり、素早いデリバリーを行いやすいです。
✅ 高い可観測性
プロセスの状態がオーケストレーターに集約されているため、監視やデバッグが容易。
✅ 理解しやすい
ワークフローが1箇所にコードとして明示的に定義されているため、全体像を把握しやすい。
デメリット
❌ 新たなコンポーネントが必要
ビジネスプロセス1つにつき、管理すべきサービスが1つ増える。
つまり、オーケストレーターを担当するチームが新たに創設されます。
そのため、その分マネジメントコストおよび調整コストはかさみます。
非同期連携になると、インフラ基盤まで新たに用意する必要があります。
❌ ロジックの漏洩リスク
本来サービスが持つべきビジネスロジックを、オーケストレーターに実装してしまうアンチパターンに陥りやすい。
これは、ドメインのロジックをアプリケーション層に実装してしまうアンチパターンのさらにマクロな世界観でのアンチパターンなので、決してないように。
❌ 中央集権化
全てのプロセスがここを経由するため、ボトルネックや単一障害点になる可能性がある。
FaaSが優秀になってきたことで、だいぶダウンしづらくなってきたとはいえ、
それでもオーケストレーター自身に負荷がかかりやすいのは変わりません。
パターン2:フロントコントローラー
ユーザーからの最初のリクエストを受け付けたサービス(起点サービス)が、オーケストレーターの役割も兼務する方式です。模式図は、下図の通り。
特徴
・注文サービスが注文プロセスのSagaの実行責務を持つなど、ドメインの中心となるサービスが関連するSagaを管理する。
・既存のコンポーネントに、サーガの責務を担わせるので、新たなコンポーネントは不要。
メリット
✅ 実装が直感的
「注文サービスが注文プロセスを管理する」のは自然な発想であり、実装しやすい。
✅ コンポーネント数が少ない
新たなサービスやインフラ基盤を用意する必要がなく、インフラ構成がシンプルになります。
デメリット
❌ 責務の肥大化
起点サービスが、自身のビジネスロジックに加えて複雑なSagaの管理ロジックも持つことになり、単一責任の原則に反する。
❌ DB管理が非常に面倒
別記事で書きますが、この場合のDB管理は
単一DBクラスター内で、下図の3つのデータを論理スキーマで完全に分離して管理
するか、もしくは
異なる種類のデータベース、つまり2~3つのDBを管理
と、非常に運用が複雑です。
❌ 密結合
Sagaのロジックが特定のサービスに強く結合するため、プロセスの変更や再利用が難しい。
❌ 循環参照のリスク
サービス間の呼び出しが複雑になり、循環参照(AがBを呼び、BがAを呼ぶ)が発生しやすくなってしまう。
パターン3:コレオグラフィ
中央の管理者が存在せず、各サービスがイベント(メッセージ)を介して自律的に連携する方式です。
特徴
・中央の指揮者(オーケストレーター)はいない。
・サービスはイベントバス(メッセージブローカー)に発行されたイベントを購読し、
自身の処理を実行した後、次のイベントを発行する。
・各サービスは「自分がどのイベントに反応し、何をするか」だけを知っていればよい。
メリット
✅ 高い独立性(疎結合)
サービスは他のサービスの存在を知る必要がなく、イベントにのみ依存する。
そのために、システムの拡張や変更が容易。
✅ 単一障害点がない
中央管理者がいないため、単一障害点のリスクがオーケストレーション型より低い。
✅ 高い回復力
一部のサービスが停止しても、イベントバスがメッセージを保持していれば、復旧後に処理を再開できる。
デメリット
❌ 全体像の把握が困難
プロセス全体が各サービスに分散しているため、ワークフローの全体像を理解するのが非常に難しい。
❌ デバッグ・監視の複雑さ
トランザクションがどこで失敗したのかを特定するには、サービスを横断したログの追跡が必要になり、監視が複雑になる。
❌ 循環依存のリスク
A→B→C→Aのようにイベントの発行がループしてしまい、無限ループに陥るリスクを慎重に避ける必要がある。
どんな時にどちらが適すのか?
どのパターンを選択するかは、トランザクションの複雑さ、システムの拡張性、開発チームの成熟度などを考慮して決定することが重要です。
よく一般的には、
複雑なプロセスにはオーケストレーション
シンプルで疎結合を重視するならコレオグラフィ
が適しているとされています。
しかし、個人的にはこれは少しミスリーディングだと思っています。
不確実性を残すうちはオーケストレーション型推奨
まだ、分散化を開始したばかりであり、複雑な業務プロセスの不確実さへの理解度が薄いうちから、コレオグラフィを選定してはいけないと私は感じています。
正常フローのみで判断してはいけません。
例外的フローにこそ、複雑さは大量に潜んでいます。
例外時のフローが、せっかくコレオグラフィにしたのに、大量のサービス間通信を生むなんてことになりかねません。これでは、コレオグラフィの良さは生かせません。
なので、その不確実さ、未知の未知なことが「カオス実験なども通してだいぶ減ってきた」
と胸を張って言い切れるまで、わたいはオーケストレーション型をお勧めします。
例外もあり
ただし、もちろん例外もあり、ステートマシン図で非常にシンプルな状態変化しか、
例外時にも辿ることがないことが判明している
補償トランザクションの失敗もほぼ起きないような超シンプルなステートマシン
コレオグラフィ型の実装に慣れているチーム
仕様変更がほぼない安定している部分
ただし、そのサービス版にが非常に大きく、テストの際のコストやデプロイ時のコストがトータルで見たら高く付いてしまっている
という5つの条件をすべて満たす場合に関しては、オーケストレーション型を介さずに、
コレオグラフィ型の検討をしてしまってもいいでしょう。
まとめ
比較表は以下の通りです。





