Saga の設計パターンは、複数のサービス間でトランザクションを調整することで、分散システムのデータの一貫性を維持するのに役立ちます。 saga は、各サービスがその操作を実行し、イベントまたはメッセージを介して次のステップを開始するローカル トランザクションのシーケンスです。 シーケンス内のステップが失敗した場合、saga は補正トランザクションを実行して完了した手順を元に戻し、データの一貫性を維持します。
コンテキストと問題
トランザクション は、複数の操作を含めることができる作業単位を表します。 トランザクション内では、イベント は、エンティティに影響を与える状態の変化を指します。 コマンド は、アクションの実行または後続のイベントのトリガーに必要なすべての情報をカプセル化します。
トランザクションは、原子性、一貫性、分離性、持続性 (ACID) の原則に従う必要があります。
- アトミック: すべての操作が成功するか、成功しないか。
- 整合性: データは有効な状態から別の状態に遷移します。
- 分離: 同時実行トランザクションは、順次トランザクションと同じ結果を生成します。
- 持続性: コミットされると、変更は失敗しても保持されます。
1 つのサービスでは、トランザクションは 1 つのデータベース内で動作するため、ACID の原則に従います。 ただし、複数のサービスで ACID コンプライアンスを実現することはより複雑です。
マイクロサービス アーキテクチャの課題
マイクロサービス アーキテクチャでは、通常、各マイクロサービスに
- 各サービスは、独自のデータをカプセル化します。
- 各サービスは、特定のニーズに最適なデータベース テクノロジとスキーマを使用できます。
- 各サービスのデータベースの独立したスケーリング。
- 1 つのサービスでのエラーは、他のサービスから分離されます。
これらの利点にもかかわらず、このアーキテクチャではサービス間のデータ整合性が複雑になります。 ACID のような従来のデータベースの保証は、複数の独立して管理されたデータ ストアに直接適用されるわけではありません。 これらの制限により、プロセス間通信 (IPC) または従来のトランザクション モデル (2 フェーズ コミット (2PC) プロトコルなど) に依存するアーキテクチャは、多くの場合、Saga パターンに適しています。
解決
Saga パターンは、トランザクションを一連のローカル トランザクション
図 1. 3 つのサービスを備えたサガ。
各ローカル トランザクション:
- 1 つのサービス内でその作業をアトミックに完了します。
- サービスのデータベースを更新します。
- イベントまたはメッセージを使用して次のトランザクションを開始します。
- ローカル トランザクションが失敗した場合、saga は一連の 補正トランザクション 実行して、前のローカル トランザクションによって行われた変更を取り消します。
Saga パターンの主要な概念
依存可能なトランザクション: 他のトランザクションが逆の効果で元に戻したり補正したりできるトランザクション。 saga のステップが失敗した場合、補正トランザクションは、依存可能なトランザクションが行った変更を元に戻します。
ピボット トランザクション: ピボット トランザクションは、saga の "戻りがないポイント" として機能します。 ピボット トランザクションが成功すると、(元に戻すことができる) 依存可能なトランザクションは関連しなくなります。 システムが一貫した最終状態を実現するには、後続のすべてのアクションが完了する必要があります。 ピボット トランザクションは、saga のフローに応じて異なるロールに分類される場合があります。
元に戻せない (非対応): 元に戻したり再試行したりすることはできません。
元に戻せる とコミットされたの間の境界: 最後に元に戻せる (依存しない) トランザクションにすることも、saga で最初に再試行可能な操作にすることもできます。
再試行可能なトランザクション: これらのトランザクションはピボット トランザクションに従います。 再試行可能なトランザクションはべき等であり、一時的なエラーが発生した場合でも、saga が最終的な状態に到達できることを確認します。 サガが最終的に一貫した状態を達成することが保証されます。
Saga の実装アプローチ
コレオグラフィ と
振り付け
振付では、サービスは一元化されたコントローラーなしでイベントを交換します。 振り付けを使用すると、各ローカル トランザクションは、他のサービスでローカル トランザクションをトリガーするドメイン イベントを発行します (図 2を参照
図 2. 振付を使ったサガ。
振付 の利点 | 振付 の欠点 |
---|---|
サービスが少なく、調整ロジックを必要としない単純なワークフローに適しています。 | 新しいステップを追加すると、ワークフローが混乱する可能性があります。 どの saga 参加者がどのコマンドに耳を傾けるかを追跡するのは困難です。 |
調整に他のサービスは必要ありません。 | 互いのコマンドを使用する必要があるため、saga 参加者間で循環依存関係が発生するリスクがあります。 |
責任は saga 参加者全体に分散されるため、単一障害点は発生しません。 | トランザクションをシミュレートするためにすべてのサービスを実行する必要があるため、統合テストは困難です。 |
オーケストレーション
オーケストレーションでは、一元化されたコントローラー (オーケストレーター) がすべてのトランザクションを処理し、イベントに基づいて実行する操作を参加者に通知します。 オーケストレーターは saga 要求を実行し、各タスクの状態を格納して解釈し、補正トランザクションを使用して障害復旧を処理します (図 3を参照
図 3. オーケストレーションを使用する saga。
オーケストレーション の |
オーケストレーション の |
---|---|
複雑なワークフローや新しいサービスを追加する場合に適しています。 | その他の設計の複雑さには、調整ロジックの実装が必要です。 |
オーケストレーターがフローを管理するため、循環依存関係を回避します。 | オーケストレーターが完全なワークフローを管理するため、障害点が発生します。 |
責任を明確に分離することで、サービス ロジックが簡略化されます。 |
問題と考慮事項
Saga パターンを実装する場合は、次の点を考慮してください。
設計思考のシフト: Saga パターンを採用するには、トランザクションの調整と複数のマイクロサービス間でのデータ整合性の確保に重点を置いて、異なる考え方が必要です。
sagasデバッグの複雑さ: 特に、参加するサービスの数が増えるにつれて、saga のデバッグは複雑になる可能性があります。
元に戻せないローカル データベースの変更: saga 参加者がそれぞれのデータベースに変更をコミットするため、データをロールバックできません。
一時的な障害とべき等の処理: システムは一時的な障害を効果的に処理し、同じ操作を繰り返しても結果が変わらないべき等性を確保する必要があります。 詳細については、べき等メッセージ処理
を参照してください。 sagasの監視と追跡の必要性: 運用上の監視を維持するには、saga のワークフローの監視と追跡が不可欠です。
補正トランザクションの制限: 補正トランザクションが常に成功するとは限らず、システムが不整合な状態になる可能性があります。
sagas の潜在的なデータ異常
データの異常とは、sagas が複数のサービス間で実行されるときに発生する可能性がある不整合です。 各サービスは独自のデータ (参加者データ) を管理するため、サービス間で分離が組み込まれている必要はありません。 このセットアップにより、部分的に適用された更新プログラムやサービス間の競合など、データの不整合や持続性の問題が発生する可能性があります。 一般的な問題は次のとおりです。
失われた更新: ある saga が別の saga によって行われた変更を考慮せずにデータを変更すると、更新が上書きまたは欠落します。
ダーティ読み取り: saga またはトランザクションが別の saga が変更したが、まだ完了していないデータを読み取るとき。
あいまい読み取り (繰り返し不可能) 読み取り: 読み取りの間に更新が行われるため、saga 内の異なるステップが不整合なデータを読み取るとき。
データの異常に対処するための戦略
これらの異常を軽減または防止するには、次の対策を検討してください。
セマンティック ロック: saga の依存可能なトランザクションがセマフォを使用して更新が進行中であることを示すアプリケーション レベルのロックを使用します。
可換更新: 同じ結果を生成しながら任意の順序で適用できるように更新プログラムを設計し、saga 間の競合を減らします。
ペシミスティック ビュー: サガのシーケンスを並べ替えて、ダーティ読み取りを排除するために再試行可能なトランザクションでデータ更新が行われるようにします。 それ以外の場合、ある saga はダーティ データ (コミットされていない変更) を読み取り、別の saga は更新をロールバックするために依存可能なトランザクションを同時に実行します。
値の再読み取り: 更新を行う前に、データが変更されていないことを検証します。 データが変更された場合は、現在の手順を中止し、必要に応じて saga を再起動します。
バージョン ファイル: レコードに対するすべての操作のログを保持し、競合を防ぐために正しい順序で実行されていることを確認します。
リスクベースのコンカレンシー (値別): 潜在的なビジネス リスクに基づいて適切なコンカレンシー メカニズムを動的に選択します。 たとえば、低リスクの更新には sagas を使用し、リスクの高い更新プログラムには分散トランザクションを使用します。
このパターンを使用する場合
次の必要がある場合は、Saga パターンを使用します。
- 厳密な結合を使用せずに、分散システムでデータの整合性を確保します。
- シーケンス内のいずれかの操作が失敗した場合は、ロールバックまたは補正します。
Saga パターンは、以下に適しています。
- 密結合トランザクション。
- 以前の参加者で発生した補正トランザクション。
- 循環依存関係。
次の手順
- 分散データ の
- リチャードソン、クリス。 2018: マイクロサービス パターン
します。 マニングパブリケーション。
関連リソース
このパターンを実装する場合は、次のパターンも役立つ場合があります。
- コレオグラフィ では、システムの各コンポーネントが、制御の中心点に依存するのではなく、ビジネス トランザクションのワークフローに関する意思決定プロセスに参加します。
- 補正トランザクション 一連の手順によって実行された作業を元に戻し、1 つ以上のステップが失敗した場合は最終的に一貫性のある操作を定義します。 複雑なビジネス プロセスとワークフローを実装するクラウドでホストされるアプリケーションは、多くの場合、この 最終的な整合性モデルに従います。
- 再試行 では、失敗した操作を透過的に再試行することで、サービスまたはネットワーク リソースに接続しようとしたときにアプリケーションが一時的な障害を処理できます。 再試行すると、アプリケーションの安定性を向上させることができます。
- サーキット ブレーカー は、リモート サービスまたはリソースに接続するときに、復旧に可変の時間がかかる障害を処理します。 サーキット ブレーカーは、アプリケーションの安定性と回復性を向上させることができます。
- 正常性エンドポイント監視 は、外部ツールが一定の間隔で公開されたエンドポイントを介してアクセスできる機能チェックをアプリケーションに実装します。 正常性エンドポイントの監視は、アプリケーションとサービスが正しく実行されていることを確認するのに役立ちます。