Saga コレオグラフィ

各サービスがイベントを発行 / 購読し、中央のオーケストレーターなしで分散トランザクションを実現する方式

分散システムトランザクション

Saga コレオグラフィとは

Saga コレオグラフィは、分散トランザクションを実現する Saga パターンの実装方式の 1 つで、各サービスがイベントを発行・購読し、中央のオーケストレーターなしで処理を連鎖させる。各サービスが自律的に動作し、イベント駆動で協調する。

Saga そのものの出発点は 1987 年の論文 (Hector Garcia-Molina・Kenneth Salem「Sagas」SIGMOD '87) で、長時間かかる 1 つのトランザクションを、個別にコミットする小さなトランザクションと、その打ち消し (補償トランザクション) の対へ分解する提案である。当初はマイクロサービスの話ではなく単一データベースの長時間トランザクション対策だった。コレオグラフィは、この分解を指揮者を置かずイベントの連鎖だけで進める形にしたものだ。

名前は分散トランザクションだが、2 相コミットのような原子性・分離性はない。各ステップが独立にコミットされるため、途中の状態は外から見えてしまう (在庫は引き当て済みだが決済は未完了、という状態が観測される)。ロールバックも「なかったことにする」処理ではなく、後から打ち消す操作を実行する取り消しである。

処理の流れ

コレオグラフィ方式では、各サービスがイベントを発行し、次のサービスがそのイベントを購読して処理を進める。中央のオーケストレーターは存在せず、サービス間がイベントで疎結合に連携する。

注文サービス: 注文作成 → "OrderCreated" イベント発行
  ↓
在庫サービス: イベント受信 → 在庫引き当て → "InventoryReserved" イベント発行
  ↓
決済サービス: イベント受信 → 支払い処理 → "PaymentCompleted" イベント発行
  ↓
配送サービス: イベント受信 → 出荷手配 → "ShipmentScheduled" イベント発行

補償トランザクション (ロールバック)

決済が失敗した場合、逆方向にイベントを発行して前のステップを取り消す。

決済サービス: 支払い失敗 → "PaymentFailed" イベント発行在庫サービス: イベント受信 → 在庫を戻す → "InventoryReleased" イベント発行注文サービス: イベント受信 → 注文をキャンセル

補償の連鎖もイベントで進むため、補償イベントが失われたり二重に届いたりすれば状態が壊れる。補償ハンドラーはべき等に書き (「在庫を 1 つ戻す」ではなく「この注文の引き当てを解放済みにする」)、配信できなかったイベントはデッドレターキューへ退避して再処理できるようにしておく。補償が失敗し続けたときに自動で整合させる手段はないため、最後は人が直す前提の運用設計になる。

AWS での実装

AWS では SNS と SQS の組み合わせが基本形になる。イベントの発行先を SNS トピックにし、購読側は SQS キューを挟んで受け取る (キューを挟まないと、購読側が落ちている間のイベントを取り落とす)。

[注文 Lambda] → SNS "OrderCreated"      → SQS → [在庫 Lambda]
[在庫 Lambda] → SNS "InventoryReserved" → SQS → [決済 Lambda]
[決済 Lambda] → SNS "PaymentCompleted"  → SQS → [配送 Lambda]

1 つのイベントを複数のサービスが受け取る必要があるときは、同じトピックに複数のキューを購読させるファンアウト構成にする。ここで注意するのは配信の保証内容である。SQS の標準キューは at-least-once 配信で、同じメッセージが 2 通以上届くことがあり、順序も維持されるとは限らない (順序は最大限の努力目標)。したがってイベントハンドラーはべき等が前提で、「同じイベントを 2 回処理しても結果が変わらない」ように書く。ステップの順序が業務上どうしても必要なら、SNS FIFO トピックと SQS FIFO キューを組み合わせて順序と重複排除を任せる。

オーケストレーションとの比較

どちらが優れているという話ではなく、フローの制御をどこに置くかの選択である。判断に効く観点を並べる。

観点コレオグラフィオーケストレーション
制御分散 (各サービスが自律)中央 (Step Functions)
結合度低い (イベントのみ)中程度 (オーケストレーターに依存)
可視性低い (フロー全体が見えにくい)高い (Step Functions で可視化)
複雑さサービス数が増えると複雑オーケストレーターが複雑さを吸収
適するケース3〜4 ステップの単純なフロー5 ステップ以上の複雑なフロー

コレオグラフィの課題

フロー全体の可視性

各サービスが独立してイベントを処理するため、「今どのステップまで進んでいるか」を把握しにくい。相関 ID (Correlation ID) を全イベントに含め、ログで追跡する。

サイクリック依存

サービス A → B → C → A のようにイベントが循環すると、無限ループが発生する。イベントの方向を一方向に保つ設計が必要だ。

DB 更新とイベント発行のずれ

ローカルトランザクションのコミットとイベント発行は別の操作なので、DB は更新できたがイベントを出す直前に落ちる (逆に、イベントは出たが DB がロールバックされる) という抜けが起きる。この隙間を埋めるのがトランザクショナルアウトボックスで、発行したいイベントを同じ DB トランザクション内でテーブルに書き、別プロセスがそれを読んで発行する。

「疎結合」の見かけと実際

コレオグラフィはサービス間の実行時の依存 (同期呼び出し) を減らすが、業務フローの知識は各サービスへ分散する。決済サービスは「InventoryReserved が来たら動く」ことを知っており、フローに 1 段足すには関係するサービスのコードを個別に触ることになる。イベントの形を変えれば購読側すべてが影響範囲だ。結合が消えるのではなく、実行時の結合が仕様上の結合に置き換わると捉えた方が実態に合う。

判断基準

  • ステップが少なく直線的 (3〜4 段程度) → コレオグラフィ。中央部品を持たない身軽さが勝つ
  • 条件分岐や並列実行が入る、段数が 5 段以上に伸びる → オーケストレーション (Step Functions に分岐と可視化を任せる)
  • 補償の順序や打ち消し条件が複雑 → オーケストレーション。完了済みステップの逆順実行を中央で保証できる

段数はあくまで目安で、実務では「フローに 1 段足すとき何箇所を触るか」で判断する方が外れにくい。触る箇所が増え始めたら、コレオグラフィの限界が近い。

どちらの方式を選ぶかより先に決めるべきなのは、どこまでを取り消せる設計にするかである。外部への送金やメール送信のように打ち消せない処理は、フローのできるだけ後ろへ寄せる。取り消せないステップより前だけで補償が完結する並びにしておけば、途中で失敗しても整合を戻せる。

この記事は役に立ちましたか?

関連用語

関連する記事