マイクロサービスにおける分散トランザクション管理のためのSagaパターンを探求。コレオグラフィー vs オーケストレーション、グローバル実装、回復力のあるシステムのベストプラクティスを理解する。
Sagaパターンをマスターする:分散トランザクション管理のグローバルガイド
今日の相互接続されたデジタル環境において、グローバル企業は、大陸やタイムゾーンを越えて顧客にサービスを提供するために、高度に分散されたシステムに依存しています。マイクロサービスアーキテクチャ、クラウドネイティブなデプロイメント、サーバーレス関数は、比類のないスケーラビリティ、回復力、開発速度を提供する、最新のアプリケーションの基盤となっています。しかし、この分散的な性質は、複数の独立したサービスとデータベースにまたがるトランザクションを管理するという重要な課題を提示します。モノリシックアプリケーション向けに設計された従来のトランザクションモデルは、これらの複雑な環境ではしばしば不十分です。ここで、Sagaパターンが、分散システムにおけるデータの整合性を実現するための、強力で不可欠なソリューションとして登場します。
この包括的なガイドでは、Sagaパターンを解明し、その基本的な原則、実装戦略、グローバルな考慮事項、およびベストプラクティスを探ります。スケーラブルな国際eコマースプラットフォームを設計するアーキテクトであろうと、回復力のある金融サービスに取り組む開発者であろうと、Sagaパターンを理解することは、堅牢な分散アプリケーションを構築するために不可欠です。
最新のアーキテクチャにおける分散トランザクションの課題
何十年もの間、ACID(原子性、整合性、分離性、永続性)トランザクションの概念は、データの整合性を保証するためのゴールドスタンダードでした。古典的な例は銀行振込です。お金は一方の口座から引き落とされ、別の口座に入金されるか、操作全体が失敗し、中間状態は残りません。この「すべてまたはなし」の保証は、通常、2フェーズコミット(2PC)などのメカニズムを使用して、単一のデータベースシステム内で実現されます。
しかし、アプリケーションがモノリシック構造から分散マイクロサービスへと進化すると、ACIDトランザクションの制限が顕著になります。
- クロスサービス境界:オンライン注文の処理など、単一のビジネスオペレーションは、Order Service、Payment Service、Inventory Service、Shipping Serviceを含む可能性があり、それぞれが独自のデータベースによって支えられています。これらのサービス間の2PCは、大きなレイテンシを導入し、サービスを緊密に結合し、単一障害点を作成します。
- スケーラビリティのボトルネック:分散2PCプロトコルでは、参加するすべてのサービスがコミットフェーズ中にロックを保持し、利用可能である必要があり、水平スケーラビリティとシステムの可用性に深刻な影響を与えます。
- クラウドネイティブな制約:多くのクラウドデータベースとメッセージングサービスは、分散2PCをサポートしておらず、従来ののアプローチを非現実的または不可能にしています。
- ネットワークレイテンシとパーティション:地理的に分散したシステム(複数のデータセンターにまたがって運用する国際的な配車アプリなど)では、ネットワークレイテンシとネットワークパーティションの可能性により、グローバル同期トランザクションは非常に望ましくなく、技術的に実現不可能になります。
これらの課題は、強力かつ即時の整合性からイベンチュアルコンシステンシーへの考え方の転換を必要とします。Sagaパターンはまさにこのパラダイムのために設計されており、すべてのサービスでデータの整合性が瞬時でなくても、ビジネスプロセスを正常に完了させることができます。
Sagaパターンの理解:はじめに
その中核として、Sagaはローカルトランザクションのシーケンスです。各ローカルトランザクションは、単一のサービス内のデータベースを更新し、次にイベントを発行し、シーケンス内の次のローカルトランザクションをトリガーします。ローカルトランザクションが失敗した場合、Sagaは一連の補償トランザクションを実行して、先行するローカルトランザクションによって行われた変更を元に戻し、システムが一貫した状態、または少なくとも失敗した試みを反映した状態に戻ることを保証します。
ここでの重要な原則は、Saga全体が従来の意味でのアトミックではない一方で、すべてのローカルトランザクションが正常に完了するか、適切な補償アクションが実行されて、完了したトランザクションの効果を逆転させることを保証することです。これにより、グローバル2PCプロトコルに依存することなく、複雑なビジネスプロセスに対するイベンチュアルコンシステンシーが実現します。
Sagaのコアコンセプト
- ローカルトランザクション:単一のサービス内で、独自のデータベースを更新するアトミックな操作。Sagaにおける最小の作業単位です。たとえば、Order Serviceの「注文の作成」や、Payment Serviceの「支払いの引き落とし」などです。
- 補償トランザクション:先行するローカルトランザクションの効果を元に戻すように設計された操作。支払いが引き落とされた場合、補償トランザクションは「支払いの払い戻し」になります。これらは、失敗した場合に整合性を維持するために不可欠です。
- Saga参加者:ローカルトランザクションを実行し、Sagaの一部として補償トランザクションを実行する可能性のあるサービス。各参加者は自律的に動作します。
- Saga実行:ビジネスプロセスを完了するローカルトランザクションと、潜在的な補償トランザクションの最初から最後までの一連の流れ。
Sagaの2つのフレーバー:オーケストレーション vs コレオグラフィー
Sagaパターンを実装するには、主に2つの方法があり、それぞれに独自の利点と欠点があります。
コレオグラフィーベースのSaga
コレオグラフィーベースのSagaでは、中央のオーケストレーターはありません。代わりに、Sagaに参加する各サービスは、イベントを生成および消費し、他のサービスからのイベントに反応します。Sagaの流れは分散されており、各サービスは、イベントに基づいて、直前と直後のステップのみを知っています。
仕組み:
ローカルトランザクションが完了すると、イベントを発行します。そのイベントに関心のある他のサービスは、独自のローカルトランザクションを実行して反応し、新しいイベントを発行する可能性があります。この連鎖反応は、Sagaが完了するまで続きます。補償も同様に処理されます。サービスが失敗した場合、失敗イベントを発行し、他のサービスに補償トランザクションを実行するようにトリガーします。
例:グローバルeコマース注文処理(コレオグラフィー)
さまざまなクラウドリージョンにサービスが分散している、グローバルeコマースプラットフォームで注文するヨーロッパの顧客を想像してください。
- Order Service:顧客が注文します。Order Serviceは注文レコードを作成し(ローカルトランザクション)、
OrderCreatedイベントをメッセージブローカー(たとえば、Kafka、RabbitMQ)に発行します。 - Payment Service:
OrderCreatedをリッスンし、Payment Serviceは地域の支払いゲートウェイを介して支払いを処理しようとします(ローカルトランザクション)。成功した場合、PaymentProcessedを発行します。失敗した場合(たとえば、資金不足、地域の支払いゲートウェイの問題)、PaymentFailedを発行します。 - Inventory Service:
PaymentProcessedをリッスンし、Inventory Serviceは、最も近い利用可能な倉庫からアイテムを予約しようとします(ローカルトランザクション)。成功した場合、InventoryReservedを発行します。失敗した場合(たとえば、すべての地域の倉庫で在庫切れ)、InventoryFailedを発行します。 - Shipping Service:
InventoryReservedをリッスンし、Shipping Serviceは予約された倉庫からの出荷をスケジュールします(ローカルトランザクション)し、ShipmentScheduledを発行します。 - Order Service:
PaymentProcessed、PaymentFailed、InventoryReserved、InventoryFailed、ShipmentScheduledをリッスンして、それに応じて注文のステータスを更新します。
コレオグラフィーでの補償トランザクション:
Inventory ServiceがInventoryFailedを発行した場合:
- Payment Service:
InventoryFailedをリッスンし、顧客に払い戻しを発行し(補償トランザクション)、RefundIssuedを発行します。 - Order Service:
InventoryFailedとRefundIssuedをリッスンし、注文ステータスをOrderCancelledDueToInventoryに更新します。
コレオグラフィーの利点:
- 疎結合:サービスは非常に独立しており、イベントを介してのみ相互作用します。
- 分散化:Saga調整のための単一障害点はありません。
- 小規模Saga向け:少数のサービスのみが関係している場合、実装が容易になる可能性があります。
コレオグラフィーの欠点:
- 多数のサービスとの複雑さ:サービスの数とステップが増えるにつれて、全体的な流れを理解することが困難になります。
- デバッグの難しさ:複数のサービスとイベントストリームにわたるSagaの実行パスを追跡することは困難になる可能性があります。
- 循環依存性のリスク:不適切なイベント設計は、サービスが独自または間接的に関連するイベントに反応し、ループを引き起こす可能性があります。
- 中央の可視性の欠如:Sagaの進捗状況または全体的なステータスを監視するための単一の場所はありません。
オーケストレーションベースのSaga
オーケストレーションベースのSagaでは、専用のSaga Orchestrator(またはコーディネーター)サービスが、Saga全体の流れを定義および管理します。オーケストレーターはSaga参加者にコマンドを送信し、その応答を待機し、次に失敗が発生した場合に補償トランザクションの実行を含め、次のステップを決定します。
仕組み:
オーケストレーターは、Sagaの状態を維持し、各参加者のローカルトランザクションを正しい順序で呼び出します。参加者は単にコマンドを実行し、オーケストレーターに応答するだけです。全体的なSagaプロセスを認識していません。
例:グローバルeコマース注文処理(オーケストレーション)
同じグローバルeコマースシナリオを使用します。
- Order Service:新しい注文リクエストを受け取り、Order Orchestrator Serviceにメッセージを送信してSagaを開始します。
- Order Orchestrator Service:
- Payment Serviceに
ProcessPaymentCommandを送信します。 - Payment Serviceから
PaymentProcessedEventまたはPaymentFailedEventを受信します。 PaymentProcessedEventの場合:- Inventory Serviceに
ReserveInventoryCommandを送信します。 InventoryReservedEventまたはInventoryFailedEventを受信します。InventoryReservedEventの場合:- Shipping Serviceに
ScheduleShippingCommandを送信します。 ShipmentScheduledEventまたはShipmentFailedEventを受信します。ShipmentScheduledEventの場合:Sagaを成功とマークします。ShipmentFailedEventの場合:補償トランザクションをトリガーします(たとえば、InventoryにUnreserveInventoryCommand、PaymentにRefundPaymentCommand)。
- Shipping Serviceに
InventoryFailedEventの場合:補償トランザクションをトリガーします(たとえば、PaymentにRefundPaymentCommand)。
- Inventory Serviceに
PaymentFailedEventの場合:Sagaを失敗とマークし、Order Serviceを直接またはイベントを介して更新します。
- Payment Serviceに
オーケストレーションでの補償トランザクション:
Inventory ServiceがInventoryFailedEventで応答した場合、Order Orchestrator Serviceは次のようになります:
- Payment Serviceに
RefundPaymentCommandを送信します。 PaymentRefundedEventを受信すると、Order Serviceを更新(またはイベントを発行)して、キャンセルを反映します。
オーケストレーションの利点:
- 明確な流れ:Sagaロジックはオーケストレーターに集中しているため、全体的な流れを理解および管理しやすくなります。
- 容易なエラー処理:オーケストレーターは、洗練された再試行ロジックと補償フローを実装できます。
- 優れた監視:オーケストレーターは、Sagaの進捗状況とステータスを追跡するための単一のポイントを提供します。
- 参加者の結合の削減:参加者は他の参加者について知る必要はありません。オーケストレーターとのみ通信します。
オーケストレーションの欠点:
- 集中コンポーネント:オーケストレーターは、高可用性とスケーラビリティのために設計されていない場合、単一障害点またはボトルネックになる可能性があります。
- より密接な結合(オーケストレーターから参加者へ):オーケストレーターは、すべての参加者のコマンドとイベントを知る必要があります。
- オーケストレーターの複雑さの増加:非常に大規模なSagaの場合、オーケストレーターのロジックが複雑になる可能性があります。
Sagaパターンの実装:グローバルシステムの実用的な考慮事項
Sagaパターンを正常に実装するには、特にグローバルユーザーベースにサービスを提供するアプリケーションの場合、いくつかの重要な側面を注意深く設計し、注意を払う必要があります。
補償トランザクションの設計
補償トランザクションは、整合性を維持するSagaパターンの能力の要です。その設計は重要であり、多くの場合、前進するトランザクションよりも複雑です。次の点を考慮してください。
- べき等性:すべてのSagaステップと同様に、補償アクションはべき等でなければなりません。払い戻しコマンドが2回送信されても、二重の払い戻しにはなりません。
- 不可逆的なアクション:一部のアクションは本当に不可逆的です(たとえば、メールの送信、カスタム製品の製造、ロケットの発射)。これらの場合、補償には、人間によるレビュー、失敗のユーザーへの通知、または直接の取り消しではなく、新しいフォローアッププロセスの作成が含まれる場合があります。
- グローバルな意味合い:国際的なトランザクションの場合、補償には、通貨換算の逆転(どのレートで?)、税金の再計算、さまざまな地域のコンプライアンス規制との調整が含まれる場合があります。これらの複雑さは、補償ロジックに組み込まれる必要があります。
Saga参加者のべき等性
Saga内のすべてのローカルトランザクションと補償トランザクションは、べき等でなければなりません。これは、同じ入力で同じ操作を複数回実行しても、1回実行した場合と同じ結果が得られる必要があることを意味します。これは、ネットワークの問題や再試行によりメッセージが重複する可能性がある分散システムにおける回復力にとって不可欠です。
たとえば、`ProcessPayment`コマンドには、一意のトランザクションIDが含まれている必要があります。Payment Serviceが同じIDで同じコマンドを2回受信した場合、1回だけ処理するか、以前の正常な処理を単に確認する必要があります。
エラー処理と再試行
分散システムでは、失敗は避けられません。堅牢なSaga実装は、次のものを考慮する必要があります。
- 一時的なエラー:一時的なネットワークの不具合、サービスの利用不可。これらは、多くの場合、自動再試行(たとえば、指数関数的なバックオフを使用)で解決できます。
- 永続的なエラー:無効な入力、ビジネスルールの違反、サービスバグ。これらは通常、補償アクションを必要とし、アラートまたは人間による介入をトリガーする可能性があります。
- デッドレターキュー(DLQ):数回の再試行後に処理できないメッセージは、Sagaをブロックしないように、後で検査と手動介入のためにDLQに移動する必要があります。
- Saga状態管理:オーケストレーター(またはイベントを介したコレオグラフィーの暗黙的な状態)は、失敗後に正しく再開または補償するために、Sagaの現在のステップを確実に保存する必要があります。
可観測性とモニタリング
複数のサービスとメッセージブローカーにまたがる分散Sagaのデバッグは、適切な可観測性がないと非常に困難になる可能性があります。包括的なログ記録、分散トレース、およびメトリックを実装することが不可欠です。
- 相関ID:Sagaに関連するすべてのメッセージとログエントリには、一意の相関IDを付加し、開発者がビジネストランザクション全体の流れを追跡できるようにする必要があります。
- 集中ログ記録:すべてのサービスからのログを中央プラットフォーム(たとえば、Elastic Stack、Splunk、Datadog)に集計します。
- 分散トレース:OpenTracingやOpenTelemetryなどのツールは、さまざまなサービスを通過するリクエストに最初から最後まで可視性を提供します。これは、Saga内のボトルネックと障害を特定する上で非常に重要です。
- メトリックとダッシュボード:成功率、失敗率、ステップごとのレイテンシ、およびアクティブなSagaの数など、Sagaの正常性と進捗状況を監視します。グローバルダッシュボードは、さまざまな地域でのパフォーマンスに関する洞察を提供し、地域の問題を迅速に特定するのに役立ちます。
オーケストレーションとコレオグラフィーの選択
選択はいくつかの要因によって異なります。
- サービスの数:多数のサービス(5以上)を含むSagaの場合、オーケストレーションは通常、より優れた保守性と明確さを提供します。サービスの数が少ない場合、コレオグラフィーで十分な場合があります。
- フローの複雑さ:複雑な条件付きロジックまたは分岐パスは、オーケストレーターで管理する方が簡単です。シンプルで線形のフローは、コレオグラフィーで機能します。
- チーム構造:チームが非常に自律的であり、中央コンポーネントを導入することを好まない場合、コレオグラフィーの方が適している可能性があります。ビジネスプロセスロジックの明確な所有者が存在する場合、オーケストレーションが適しています。
- 監視要件:Sagaの進捗状況の強力で集中化された監視が重要である場合、オーケストレーターがこれを容易にします。
- 進化:新しいステップまたは補償ロジックが導入されるにつれて、コレオグラフィーは進化することがより困難になる可能性があり、複数のサービスでの変更が必要になる可能性があります。オーケストレーションの変更は、オーケストレーターに局所的に行われます。
Sagaパターンを採用する場合
Sagaパターンは、すべてのトランザクション管理ニーズに対する万能薬ではありません。特定のシナリオに特に適しています。
- マイクロサービスアーキテクチャ:ビジネスプロセスが、それぞれ独自のデータストアを持つ複数の独立したサービスにまたがる場合。
- 分散データベース:トランザクションが、異なるデータベースインスタンス、または異なるデータベーステクノロジー(たとえば、リレーショナル、NoSQL)間でデータを更新する必要がある場合。
- 長時間実行されるビジネスプロセス:従来のロックを保持することが非現実的な、完了にかなりの時間がかかる可能性のある操作の場合。
- 高可用性とスケーラビリティ:システムが高可用性と水平スケーラビリティを維持する必要があり、同期2PCが許容できない結合またはレイテンシを導入する場合。
- クラウドネイティブなデプロイメント:従来の分散トランザクションコーディネーターが利用できないか、クラウドの弾力的な性質と相容れない環境。
- グローバルオペレーション:ネットワークレイテンシにより同期分散トランザクションが実行不可能な、複数の地理的地域にまたがるアプリケーションの場合。
グローバル企業向けのSagaパターンの利点
グローバル規模で事業を展開する組織にとって、Sagaパターンは大きなメリットをもたらします。
- スケーラビリティの強化:分散ロックと同期呼び出しを排除することにより、サービスは個別にスケーリングし、高量の同時トランザクションを処理できます。これは、ピーク時のグローバルトラフィック時間(たとえば、さまざまなタイムゾーンに影響を与える季節的な販売)に不可欠です。
- 回復力の向上:Sagaの一部での障害は、必ずしもシステム全体を停止させるわけではありません。補償トランザクションにより、システムはエラーを適切に処理し、回復するか、一貫した状態に戻り、グローバルな運用におけるダウンタイムとデータの不整合を最小限に抑えることができます。
- 疎結合:サービスは独立したままで、非同期イベントまたはコマンドを介して通信します。これにより、さまざまな地域の開発チームが自律的に作業し、他のサービスに影響を与えることなくアップデートを展開できます。
- 柔軟性と俊敏性:ビジネスロジックをより簡単に進化させることができます。Sagaに新しいステップを追加したり、既存のステップを変更したりしても、特にオーケストレーションでは、ローカライズされた影響しかありません。この適応性は、進化するグローバル市場の需要や規制の変更に対応するために不可欠です。
- グローバルリーチ:Sagaは本質的に非同期通信をサポートしているため、地理的に分散したデータセンター、異なるクラウドプロバイダー、または異なる国のパートナーシステム間のトランザクションの調整に最適です。これにより、ネットワークレイテンシや地域のインフラストラクチャの違いに妨げられることなく、真にグローバルなビジネスプロセスが促進されます。
- 最適化されたリソース利用:サービスは、データベース接続やロックを長時間保持する必要がないため、リソースのより効率的な使用と運用コストの削減につながります。これは、動的なクラウド環境で特に有利です。
課題と考慮事項
強力ですが、Sagaパターンには課題がないわけではありません。
- 複雑さの増大:単純なACIDトランザクションと比較して、Sagaは、より多くの可動部分(イベント、コマンド、オーケストレーター、補償トランザクション)を導入します。この複雑さには、慎重な設計と実装が必要です。
- 補償アクションの設計:効果的な補償トランザクションの作成は、特に外部的な副作用があるアクションや、論理的に不可逆的なアクションの場合、些細なことではありません。
- イベンチュアルコンシステンシーの理解:開発者とビジネスステークホルダーは、データの整合性が即時ではなく、最終的に達成されることを理解する必要があります。これには、考え方の変化と、ユーザーエクスペリエンス(たとえば、すべてのSagaステップが完了するまで注文を「保留中」として表示する)の慎重な検討が必要です。
- テスト:Sagaの統合テストはより複雑であり、通常のパスと、補償を含むさまざまな障害モードの両方をテストするシナリオが必要です。
- ツールとインフラストラクチャ:堅牢なメッセージングシステム(たとえば、Apache Kafka、Amazon SQS/SNS、Azure Service Bus、Google Cloud Pub/Sub)、Saga状態の信頼性の高いストレージ、および洗練された監視ツールが必要です。
グローバルSaga実装のベストプラクティス
Sagaパターンの利点を最大化し、課題を軽減するために、これらのベストプラクティスを検討してください。
- 明確なSaga境界の定義:Sagaを構成する要素と、個々のローカルトランザクションを明確に区別します。これにより、複雑さを管理し、補償ロジックが明確に定義されていることを確認できます。
- べき等性の高い操作の設計:強調したように、すべてのローカルトランザクションと補償トランザクションが、意図しない副作用なしに複数回実行できることを確認します。
- 堅牢な監視とアラートの実装:相関ID、分散トレース、および包括的なメトリックを活用して、Sagaの実行に関する深い可視性を得ます。Sagaの失敗や、人による介入が必要な補償アクションのアラートを設定します。
- 信頼性の高いメッセージングシステムの活用:保証されたメッセージ配信(少なくとも1回配信)と堅牢な永続性を提供するメッセージブローカーを選択します。デッドレターキューは、処理できないメッセージを処理するために不可欠です。
- 重大な障害については、人間の介入を検討してください:自動補償が不十分であるか、データの整合性を危険にさらす状況(たとえば、重大な支払い処理の失敗)については、人間の監督と手動解決のための経路を設計します。
- Sagaフローを徹底的に文書化する:その分散的な性質を考慮すると、Sagaステップ、イベント、コマンド、および補償ロジックの明確なドキュメントは、理解、メンテナンス、および新しいチームメンバーのオンボーディングに不可欠です。
- UI/UXにおけるイベンチュアルコンシステンシーを優先する:操作が完了するまで、UIをイベンチュアルコンシステンシーモデルを反映するように設計し、進行中の操作がある場合にユーザーにフィードバックを提供します。
- 障害シナリオのテスト:通常のパスに加えて、すべての可能な障害ポイントと対応する補償ロジックを厳密にテストします。
分散トランザクションの未来:グローバルな影響
マイクロサービスとクラウドネイティブアーキテクチャが引き続きエンタープライズITを支配するにつれて、効果的な分散トランザクション管理の必要性は高まる一方です。Sagaパターンは、イベンチュアルコンシステンシーと回復力に焦点を当てており、グローバルインフラストラクチャ全体でシームレスに運用できる、スケーラブルで高性能なシステムを構築するための基本的なアプローチとして、今後も存続する態勢が整っています。
オーケストレーター用のステートマシンフレームワーク、改善された分散トレース機能、マネージドメッセージブローカーなど、ツールの進歩により、Sagaの実装と管理がさらに簡素化されます。モノリシックで密接に結合されたシステムから、疎結合された分散サービスへの移行は基本であり、Sagaパターンは、この変革の重要なイネーブラーであり、企業がデータの整合性に自信を持って、グローバルに革新し、拡大することを可能にします。
結論
Sagaパターンは、複雑なマイクロサービス環境、特にグローバルな視聴者にサービスを提供する環境で、分散トランザクションを管理するためのエレガントで実用的なソリューションを提供します。イベンチュアルコンシステンシーを採用し、コレオグラフィーまたはオーケストレーションのいずれかを採用することにより、組織は、従来のACIDトランザクションの制限を克服する、高度にスケーラブルで、回復力があり、柔軟なアプリケーションを構築できます。
独自の複雑さを導入しますが、思慮深い設計、補償トランザクションの綿密な実装、および堅牢な可観測性が、そのすべての力を活用するための鍵です。真にグローバルで、クラウドネイティブなプレゼンスを構築することを目指す企業にとって、Sagaパターンを習得することは、単なる技術的な選択ではなく、国境を越えたさまざまな運用環境でのデータの整合性と事業継続性を確保するための戦略的な必須事項です。