

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# Saga コレオグラフィパターン
<a name="saga-choreography"></a>

## Intent
<a name="saga-choreography-intent"></a>

Saga コレオグラフィパターンは、イベントサブスクリプションを使用することで、複数のサービスにまたがる分散トランザクションのデータ完全性を維持するのに役立ちます。分散トランザクションでは、トランザクションが完了する前に複数のサービスを呼び出すことができます。異なるデータストアにサービスがデータを保存する場合、これらのデータストア間でデータ整合性を維持するのが難しい場合があります。

## 導入する理由
<a name="saga-choreography-motivation"></a>

*トランザクション*とは、複数のステップを含む可能性のある単一の作業単位です。すべてのステップが完全に実行されるか、まったく実行されないため、データストアは整合した状態を保持します。*アトミック性、整合性、分離性、耐久性 (ACID)* という用語によって、トランザクションの特性が定義されます。リレーショナルデータベースは ACID トランザクションを提供してデータ整合性を維持します。

トランザクションの整合性を維持するため、リレーショナルデータベースでは 2 フェーズコミット (2PC) 方式を使用します。これは*準備フェーズ*と*コミットフェーズ*で構成されます。
+ 準備フェーズでは、調整プロセスはトランザクションを構成するプロセス (構成プロセス) に、トランザクションをコミットするかロールバックするかを約束するように要求します。
+ コミットフェーズでは、調整プロセスが構成プロセスにトランザクションのコミットを要求します。準備フェーズで構成プロセスがコミットに同意できない場合、トランザクションはロールバックされます。

Database-per-service 設計パターンに従う分散システムでは、2 フェーズコミットは選択肢になりません。これは、各トランザクションがさまざまなデータベースに分散され、リレーショナルデータストアの 2 フェーズコミットと同様にプロセスを調整できる単一のコントローラーが存在しないためです。この場合の解決策の 1 つは、Saga コレオグラフィパターンを使用することです。

## 適用対象
<a name="saga-choreography-applicability"></a>

Saga コレオグラフィパターンは次のような場合に使用します。
+ 複数のデータストアにまたがる分散トランザクションのデータ完全性と整合性がシステムに求められる場合。
+ データストア (NoSQL データベースなど) が 2PC を用意して ACID トランザクションに対応していない場合で、1 つのトランザクション内で複数のテーブルを更新する必要があり、アプリケーションの境界内で 2PC を実装する作業が複雑な場合。
+ 構成プロセスのトランザクションを管理するセントラル制御プロセスが、単一障害点になる可能性がある場合。
+ Saga の構成プロセスが独立したサービスであり、疎結合にする必要がある場合。
+ ビジネスドメインのコンテキスト境界にまたがったコミュニケーションがある場合。

## 問題点と考慮事項
<a name="saga-choreography-issues"></a>
+ **複雑さ: **マイクロサービスの数が増えるにつれて、マイクロサービス間のやり取りの数が増えるため、Saga コレオグラフィを管理するのが難しくなる可能性があります。さらに、補償トランザクションや再試行によってアプリケーションコードが複雑になり、メンテナンスのオーバーヘッドが発生する可能性があります。コレオグラフィは、Saga を構成しているサービスが少なく、単一障害点のないシンプルな実装が必要な場合に適しています。構成しているサービスが増えると、このパターンを使用して構成しているサービス間の依存関係を追跡するのが難しくなります。
+ **回復力のある実装:** Saga コレオグラフィでは、Saga オーケストレーションと比べて、タイムアウト、再試行、その他の回復パターンをグローバルに実装するのが難しくなります。コレオグラフィはオーケストレーターレベルではなく、個々のコンポーネントに実装する必要があります。
+ **循環的な依存関係:** 構成しているサービスはお互いに発行したメッセージを使用します。その結果、依存関係が循環的に発生して、コードが複雑になり、メンテナンスのオーバーヘッドが発生し、デッドロックの可能性も発生します。
+ **二重書き込みの問題: **マイクロサービスはアトミックにデータベースを更新し、イベントを発行する必要があります。いずれかのオペレーションが失敗すると、不整合な状態になる可能性があります。これを解決する 1 つの方法は、[トランザクションアウトボックスパターン](transactional-outbox.md)を使用することです。
+ **イベントの保存: **Saga を構成するサービスは、発行されたイベントに基づいてアクションを実行します。監査、デバッグ、再生のために、イベントを発生順に保存することが重要です。データ整合性を回復するためにシステム状態を再生する必要がある場合に備えて、[イベントソーシングパターン](event-sourcing.md)を使用してイベントをイベントストアに保存できます。イベントストアにはシステム内のすべての変更が反映されるため、監査やトラブルシューティングにも使用できます。
+ **結果整合性**: ローカルトランザクションを順次処理することで結果整合性が保たれます。これは、強い整合性を必要とするシステムでは課題となることがあります。この問題を解決するには、整合性モデルに対するビジネスチームの期待を設定するか、ユースケースを再評価して、強固な整合性を備えたデータベースに切り替えます。
+ **冪等性**: Saga を構成するサービスには、予期しないクラッシュやオーケストレーターの障害によって一時的な障害が発生した場合に繰り返し実行できるように冪等性が必要です。
+ **トランザクションの分離**: saga パターンには、ACID トランザクションの 4 つの特性の 1 つであるトランザクション分離機能がありません。トランザクションの[分離度](https://docs.aws.amazon.com/neptune/latest/userguide/transactions-isolation-levels.html)によって、トランザクションが処理するデータに他の同時トランザクションがどの程度影響する可能性があるかが決まります。トランザクションの同時オーケストレーションによって、最新でないデータが発生する可能性があります。このようなシナリオに対処するために、セマンティックロックを使用することをお勧めします。
+ **オブザーバビリティ**: オブザーバビリティとは、実装とオーケストレーションのプロセスにおける問題をトラブルシューティングするための、詳細なログ記録とトレースを指します。これは、Saga を構成するサービスが増え、デバッグが複雑になる場合に重要になります。Saga コレオグラフィでは、Saga オーケストレーションと比べて、エンドツーエンドのモニタリングとレポーティングを実現するのが困難です。
+ **レイテンシーの問題**: Saga が複数のステップで構成されている場合、補償トランザクションによって全体の応答時間にレイテンシーが加わることがあります。トランザクションが同期呼び出しを行うと、レイテンシーがさらに大きくなる可能性があります。

## 実装
<a name="saga-choreography-implementation"></a>

### 高レベルのアーキテクチャ
<a name="saga-choreography-high-level-arch"></a>

以下のアーキテクチャ図では、Saga コレオグラフィは、注文サービス、在庫サービス、支払いサービスの 3 つで構成されています。トランザクションを完了するには、T1、T2、T3 の 3 ステップが必要です。3 つの補償トランザクション (C1、C2、C3) によってデータが初期状態に戻ります。

![Saga コレオグラフィの概要レベルのアーキテクチャ](http://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/cloud-design-patterns/images/saga-choreography-1.png)

+ 注文サービスはローカルトランザクション T1 を実行します。このトランザクションはデータベースをアトミックに更新し、`Order placed` メッセージをメッセージブローカーに発行します。
+ 在庫サービスは注文サービスのメッセージをサブスクライブし、注文が作成されたというメッセージを受信します。
+ 在庫サービスはローカルトランザクション T2 を実行します。このトランザクションはデータベースをアトミックに更新し、`Inventory updated` メッセージをメッセージブローカーに発行します。
+ 支払いサービスは在庫サービスからのメッセージをサブスクライブし、在庫が更新されたというメッセージを受信します。
+ 支払いサービスはローカルトランザクション T3 を実行します。このトランザクションはデータベースに支払いの詳細を付け加えてアトミックに更新し、`Payment processed` メッセージをメッセージブローカーに発行します。
+ 支払いが失敗した場合、支払いサービスは補償トランザクション C1 を実行します。これにより、データベース内の支払いがアトミックに元に戻され、`Payment failed` メッセージがメッセージブローカーに発行されます。
+ 補償トランザクション C2 と C3 は、データの整合性を復元するために実行されます。

### AWS のサービスを使用した実装
<a name="saga-choreography-aws-services"></a>

Saga コレオグラフィパターンは Amazon EventBridge を使用して実装できます。EventBridge はイベントを使用してアプリケーションコンポーネントを接続します。イベントバスまたはパイプを介してイベントを処理します。イベントバスは、[イベント](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-events.html)を受信して、ゼロ個以上の送信先 (ターゲット) に配信するルーターです。[イベントバスに関連付けられたルール](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-rules.html)によって、受信したイベントが評価され、処理のために[ターゲット](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-targets.html)に送信されます。

以下のアーキテクチャは次のような構成です。
+ マイクロサービス (注文サービス、在庫サービス、支払いサービス) は Lambda 関数として実装されます。
+ カスタム EventBridge バスには、`Orders` イベントバス、`Inventory` イベントバス、`Payment` イベントバスの 3 つがあります。
+ `Orders` ルール、`Inventory` ルール、`Payment` ルールは、対応するイベントバスに送信されるイベントに一致し、Lambda 関数を呼び出します。

![AWS のサービスを利用した Saga コレオグラフィアーキテクチャ](http://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/cloud-design-patterns/images/saga-choreography-2.png)


成功したシナリオでは、注文が入ると以下の処理が実行されます。

1. 注文サービスはリクエストを処理し、イベントを `Orders` イベントバスに送信します。

1. `Orders` ルールがイベントに一致し、在庫サービスが開始されます。

1. 在庫サービスは在庫を更新し、イベントを `Inventory` イベントバスに送信します。

1. `Inventory` ルールがイベントに一致し、支払いサービスが開始されます。

1. 支払いサービスは支払いを処理し、イベントを `Payment` イベントバスに送信します。

1. `Payment` ルールがイベントに一致し、`Payment processed` イベント通知をリスナーに送信します。

   一方、注文処理に問題がある場合は、EventBridge ルールは、データ整合性と完全性を維持するために、データ更新を元に戻すための補償トランザクションを開始します。

1. 支払いが失敗した場合、`Payment` ルールはイベントを処理し、在庫サービスを開始します。在庫サービスは補償トランザクションを実行して在庫を元に戻します。

1. 在庫が元に戻されると、在庫サービスは `Inventory reverted` イベントを `Inventory` イベントバスに送信します。このイベントは `Inventory` ルールによって処理されます。注文サービスを開始し、補償トランザクションを実行して注文を削除します。

## 関連情報
<a name="saga-choreography-resources"></a>
+ [Saga オーケストレーションパターン](saga-orchestration.md)
+ [トランザクションアウトボックスパターン](transactional-outbox.md)
+ [バックオフパターンで再試行](retry-backoff.md)