編集

次の方法で共有


Saga 分散トランザクション パターン

Azure

Saga の設計パターンは、複数のサービス間でトランザクションを調整することで、分散システムのデータの一貫性を維持するのに役立ちます。 saga は、各サービスがその操作を実行し、イベントまたはメッセージを介して次のステップを開始するローカル トランザクションのシーケンスです。 シーケンス内のステップが失敗した場合、saga は補正トランザクションを実行して、完了した手順を元に戻します。 この方法は、データの一貫性を維持するのに役立ちます。

コンテキストと問題

トランザクション は、複数の操作を含めることができる作業単位を表します。 トランザクション内では、イベント は、エンティティに影響を与える状態変更を参照します。 コマンド は、アクションの実行または後続のイベントのトリガーに必要なすべての情報をカプセル化します。

トランザクションは、原子性、一貫性、分離性、持続性 (ACID) の原則に従う必要があります。

  • アトミック性: すべての操作が成功するか、操作が成功しなかったか。
  • 整合性: データは有効な状態から別の有効な状態に切り替わります。
  • 分離: 同時実行トランザクション、シーケンシャル トランザクションと同じ結果が得られます。
  • 持続性: 変更は、エラーが発生した場合でも、コミット後も保持されます。

1 つのサービスでは、トランザクションは 1 つのデータベース内で動作するため、ACID の原則に従います。 ただし、複数のサービスで ACID コンプライアンスを実現する方が複雑になる場合があります。

マイクロサービス アーキテクチャの課題

マイクロサービス アーキテクチャは、通常、各マイクロサービス 専用データベースを割り当てます。 この方法には、いくつかの利点があります。

  • 各サービスは、独自のデータをカプセル化します。
  • 各サービスは、特定のニーズに最適なデータベース テクノロジとスキーマを使用できます。
  • 各サービスのデータベースは、個別にスケーリングできます。
  • 1 つのサービスでのエラーは、他のサービスから分離されます。

これらの利点にもかかわらず、このアーキテクチャではサービス間のデータ整合性が複雑になります。 ACID のような従来のデータベースの保証は、複数の独立して管理されたデータ ストアに直接適用されるわけではありません。 これらの制限により、プロセス間通信または 2 フェーズ コミット プロトコルなどの従来のトランザクション モデルに依存するアーキテクチャは、多くの場合、Saga パターンに適しています。

解決

Saga パターンは、トランザクションを一連のローカル トランザクション 分割することによって管理します。

概要を示す図。

各ローカル トランザクション:

  1. 1 つのサービス内でその作業をアトミックに完了します。
  2. サービスのデータベースを更新します。
  3. イベントまたはメッセージを使用して次のトランザクションを開始します。

ローカル トランザクションが失敗した場合、saga は一連の 補正トランザクション 実行して、前のローカル トランザクションが行った変更を元に戻します。

Saga パターンの主要な概念

  • 依存できないトランザクション は、元に戻したり、反対の効果を持つ他のトランザクションによって補正したりできます。 saga のステップが失敗した場合、補正トランザクションは、依存可能なトランザクションが行った変更を元に戻します。

  • Pivot トランザクション、saga でのリターンのポイントとして機能します。 ピボット トランザクションが成功すると、依存可能なトランザクションは関連しなくなります。 システムが一貫した最終状態を実現するには、後続のすべてのアクションを完了する必要があります。 ピボット トランザクションは、saga のフローに応じて、異なるロールを引き受けることができます。

    • 元に戻せないトランザクションまたは互換性のないトランザクション 元に戻したり再試行したりすることはできません。

    • 取り消し可能なトランザクションとコミットされた の境界は、ピボット トランザクションが最後に元に戻せるトランザクション、または取り消し可能なトランザクションであることを意味します。 または、saga の最初の再試行可能な操作を指定することもできます。

  • 再試行可能なトランザクション ピボット トランザクションに従います。 再試行可能なトランザクションはべき等であり、一時的なエラーが発生した場合でも、saga が最終的な状態に到達できるようにします。 彼らは最終的に一貫した状態を達成するためにサガを助ける。

Saga の実装アプローチ

2 つの一般的な saga 実装アプローチは、振り付け とオーケストレーション です。 各アプローチには、ワークフローを調整するための独自の課題とテクノロジのセットがあります。

振り付け

振付手法では、サービスは集中型コントローラーなしでイベントを交換します。 振り付けを使用すると、各ローカル トランザクションは、他のサービスでローカル トランザクションをトリガーするドメイン イベントを発行します。

振付を使用したサガを示す図。

振付の利点 振付の欠点
サービスが少なく、調整ロジックを必要としない単純なワークフローに適しています。 新しい手順を追加すると、ワークフローが混乱する可能性があります。 各 saga 参加者が応答するコマンドを追跡するのは困難です。
調整に他のサービスは必要ありません。 互いのコマンドを使用する必要があるため、saga 参加者間で循環依存関係が発生するリスクがあります。
責任は saga 参加者全体に分散されるため、単一障害点は発生しません。 統合テストは、トランザクションをシミュレートするためにすべてのサービスを実行する必要があるため、困難です。

オーケストレーション

オーケストレーションでは、一元化されたコントローラーまたは オーケストレーターは、すべてのトランザクションを処理し、イベントに基づいて実行する操作を参加者に指示します。 オーケストレーターは saga 要求を実行し、各タスクの状態を格納および解釈し、補正トランザクションを使用して障害復旧を処理します。

オーケストレーションを使用した saga を示す図。

オーケストレーションの利点 オーケストレーションの欠点
複雑なワークフローや新しいサービスを追加する場合に適しています。 その他の設計の複雑さには、調整ロジックの実装が必要です。
オーケストレーターがフローを管理するため、循環依存関係を回避します。 オーケストレーターが完全なワークフローを管理するため、障害点が発生します。
責任を明確に分離することで、サービス ロジックが簡略化されます。

問題と考慮事項

このパターンを実装する方法を決定するときは、次の点を考慮してください。

  • デザイン思考のシフト: サガパターンを採用するには別の考え方が必要です。 複数のマイクロサービス間のトランザクション調整とデータ整合性に重点を置く必要があります。

  • デバッグ の複雑さ: デバッグ のサガは、特に参加するサービスの数が増えるにつれて複雑になる場合があります。

  • 元に戻せないローカル データベースの変更: saga 参加者がそれぞれのデータベースに変更をコミットするため、 データをロールバックできません。

  • 一時的な障害とべき等性の処理: システムは、一時的な障害を効果的に処理し、同じ操作を繰り返しても結果が変更されないようにする必要があります。 詳細については、べき等メッセージ処理を参照してください。

  • saga の監視と追跡の必要性: saga のワークフローの監視と追跡は、運用上の監視を維持するために不可欠なタスクです。

  • 補正トランザクションの制限事項: 補正トランザクションが必ずしも成功するとは限らないため、システムが不整合な状態になる可能性があります。

sagas の潜在的なデータ異常

データの異常は、sagas が複数のサービスにわたって動作するときに発生する可能性がある不整合です。 各サービスは、参加要素データと呼ばれる独自のデータを管理するため、サービス間で組み込みの分離はありません。 このセットアップにより、部分的に適用された更新プログラムやサービス間の競合など、データの不整合や持続性の問題が発生する可能性があります。 一般的な問題は次のとおりです。

  • 失われた更新: ある saga が別の saga による変更を考慮せずにデータを変更すると、更新が上書きされたり、更新が失われたりします。

  • ダーティ読み取り: 別の saga が変更したデータを saga またはトランザクションが読み取ったが、変更が完了していない場合。

  • あいまい読み取り (繰り返し不可) : 読み取りの間に更新が行われるため、saga 内の異なる手順で不整合なデータが読み取られた場合。

データの異常に対処するための戦略

これらの異常を軽減または防止するには、次の対策を検討してください。

  • セマンティック ロック: saga の依存可能なトランザクションがセマフォを使用して更新が進行中であることを示す場合は、アプリケーション レベルのロックを使用します。

  • 可換更新: 同じ結果を生成しながら、任意の順序で適用できるように、更新プログラムを設計します。 この方法は、sagas 間の競合を減らすのに役立ちます。

  • ペシミスティック ビュー: ダーティ読み取りを排除するために再試行可能なトランザクションでデータ更新が行われるように、saga のシーケンスを並べ替えます。 それ以外の場合は、1 つの saga がダーティ データを読み取ったり、コミットされていない変更 したり、別の saga が同時に更新をロールバックするために修復可能なトランザクションを実行したりします。

  • 再読み取り値: 更新する前にデータが変更されていないことを確認します。 データが変更された場合は、現在の手順を停止し、必要に応じて saga を再起動します。

  • バージョン ファイル: レコードに対して実行されたすべての操作のログを保持し、競合を防ぐために正しい順序で実行されるようにします。

  • 値に基づくリスクベースのコンカレンシー: 潜在的なビジネス リスクに基づいて適切なコンカレンシー メカニズムを動的に選択します。 たとえば、低リスクの更新には sagas を使用し、リスクの高い更新では分散トランザクションを使用します。

このパターンを使用する場合

このパターンは、次の場合に使用します。

  • 厳密な結合を使用せずに、分散システムでデータの整合性を確保する必要があります。
  • シーケンス内のいずれかの操作が失敗した場合は、ロールバックまたは補正する必要があります。

このパターンは、次の場合に適さない場合があります。

  • トランザクションは密接に結合されます。
  • 補正トランザクションは、以前の参加者で発生します。
  • 循環依存関係があります。

次の手順

  • クラウドネイティブ データ パターン する

このパターンを実装する場合、次のパターンが関連する場合があります。

  • の振り付けパターン では、システムの各コンポーネントが、制御の中心点に依存するのではなく、ビジネス トランザクションのワークフローに関する意思決定プロセスに参加します。

  • 補正トランザクション パターン 一連の手順によって実行される作業を元に戻し、1 つ以上のステップが失敗した場合に一貫した操作を最終的に定義します。 複雑なビジネス プロセスとワークフローを実装するクラウドでホストされるアプリケーションは、多くの場合、この 最終的な整合性モデルに従います。

  • 再試行パターン を使用すると、失敗した操作を透過的に再試行してサービスまたはネットワーク リソースに接続しようとしたときに、アプリケーションで一時的なエラーを処理できます。 このパターンにより、アプリケーションの安定性を向上させることができます。

  • サーキット ブレーカー パターン は、リモート サービスまたはリソースに接続するときに、復旧に可変の時間がかかる障害を処理します。 このパターンにより、アプリケーションの安定性と回復性が向上します。

  • 正常性エンドポイント監視パターン は、外部ツールが一定の間隔で公開されたエンドポイントを介してアクセスできる機能チェックをアプリケーションに実装します。 このパターンは、アプリケーションとサービスが正しく実行されていることを確認するのに役立ちます。