複数のサービスにわたるトランザクション操作。狂気へのメソッド。

Mary-Kate Olsen
リリース: 2024-11-17 00:21:03
オリジナル
709 人が閲覧しました

Transactional Operations Across Multiple Services. A Method To The Madness.

マイクロサービス環境でチームが対処しなければならない多くの複雑さの 1 つはトランザクションです。複数のマイクロサービスにまたがるトランザクション。モノリシック アプリケーションとは異なり、トランザクションは通常、単一のデータベースと @Transactional
で管理されます。 アノテーションを使用すると、マイクロサービスでは、多くの場合、各サービスが独自のデータベースを持ち、分散トランザクションがより複雑になります。ここでは、Spring Boot でこれらの分散トランザクションを効果的に処理する方法についてのガイドを示します。

まず、トランザクションとは何かについて同意することから始めましょう。

トランザクションは、単一の分割不可能な操作として扱われる、コンピューティング環境またはデータベース環境における作業単位です。これは、すべてが一緒に成功するか一緒に失敗する必要がある一連のアクションまたはステップを表し、予期しないイベント (停電やネットワーク障害など) が発生した場合でも、データの一貫性と整合性を確保します

データベースのコンテキストでは、トランザクションにはレコードの作成、更新、削除などの複数のクエリが含まれる場合があります。トランザクションは通常、ACID プロパティとして知られる 4 つの必須プロパティに従います。

a. 原子性 - トランザクション内のすべての操作は単一の単位として扱われます。すべての操作が成功するか、何も成功しないかのどちらかです。

b. 一貫性 - トランザクションはシステムをある有効な状態から別の有効な状態に移行させ、データの有効性を維持します。

c. 分離 - トランザクションは分離して実行されます。つまり、中間状態は他のトランザクションからは見えません。

d. 耐久性 - トランザクションがコミットされると、その変更は永続的になり、システムがクラッシュしても存続します。


短編小説

賑やかな e コマース アプリで、顧客のアリスが新しいラップトップ、アクセサリ、特急配送を注文していると想像してください。ここでは、彼女の注文が OrderSagaOrchestrator によって管理されるシステム内をどのように流れるかについての舞台裏のストーリーをご紹介します。

賑やかな e コマース アプリで、顧客のアリスが新しいラップトップ、アクセサリ、特急配送を注文していると想像してください。ここでは、彼女の注文が OrderSagaOrchestrator によって管理されるシステム内をどのように流れるかについての舞台裏のストーリーをご紹介します。

アリスは、支払いと配送情報を入力した後、「今すぐ注文」をクリックします。このアクションにより、サーガと呼ばれるプロセスが開始されます。これは、彼女の注文が最初から最後まで正しく処理されることを保証するために慎重に調整された一連のトランザクションです。

ステップ 1: 支払い処理
物語のオーケストレーターはまず PaymentService を確認し、アリスのアカウントから必要な金額を差し引く呼び出しを開始します。 paymentService.processPayment() メソッドが呼び出され、アリスの支払いが承認されます。

ステップ 2: 在庫の予約
支払いが成功すると、オーケストレーターは InventoryService に移動し、そこでアリス用の特定のラップトップ モデルとアクセサリを予約します。この予約ステップは、注文の処理中に在庫が売り切れたり、別の顧客に渡されたりすることのないように非常に重要です。

ステップ 3: 発送の開始
在庫が正常に予約されると、saga Orchestrator は ShippingService に接続します。ここで、shippingService.initiate Shipping() は物流を開始し、商品が梱包されてアリスの住所に発送できる状態にします。

障害の処理: 補償ロジック

しかし、分散環境では、どの段階でも問題が発生する可能性があります。物流上のエラーにより出荷の開始が失敗した場合、または在庫の不一致により在庫を実際に履行できない場合はどうなるでしょうか?オーケストレーターには報酬戦略が用意されています。

例外がスローされた場合、オーケストレーターは補償トランザクションを開始してプロセス全体をロールバックするため、アリスは受け取らないアイテムに対して料金を請求されません。

3.1.出荷のキャンセル - オーケストレーターは ShippingService.cancel Shipping() を呼び出し、出荷を停止します。

3.2.在庫のリリース - 次に、inventoryService.releaseInventory() をトリガーし、アリスの予約アイテムを解放して、他の顧客が購入できるようにします。

3.3. Refund Payment - 最後に、paymentService.refund() を呼び出して、Alice の支払いを返金し、注文に対して請求されないようにします。

最終的に、この調整された物語により、アリスのエクスペリエンスはスムーズかつ一貫したものになり、問題が発生した場合でも、システムの整合性を維持する方法で解決されます。これは、マイクロサービスにおける分散トランザクションと補償ロジックの魔法です。


トランザクションとは何かを理解し、これが役立つ実際のシナリオを理解したところで、分散環境でこれを機能させる方法について詳しく見ていきましょう。

この問題を解決するためにチームが利用する主要なアプローチがあります

1. SAGA パターン: マイクロサービス アーキテクチャで分散トランザクションを処理するために最も広く使用されているパターンの 1 つは、Saga パターンです。サガは、各サービスが独立して実行する一連のローカル トランザクションです。物語の各ステップは、物語が失敗した場合にそれを元に戻すアクションによって補われます。

Saga パターンは主に 2 つの方法で実装できます:

  1. a. コレオグラフィーベースの SAGA: トランザクションに関与する各サービスはイベントをリッスンし、トランザクションを実行します。完了すると、物語の次のステップをトリガーするイベントが発行されます。ステップが失敗した場合、補償イベントがトリガーされ、前のステップが取り消されます。

  2. b. オーケストレーションベースの SAGA: 集中型サービス (Saga オーケストレーター) が、Saga のステップを調整します。動作の順序を決定し、障害が発生した場合の補償を管理します。

2. 2 フェーズ コミット (2PC): 2 フェーズ コミット プロトコルはモノリシック システムで一般的に使用されますが、Amitikos や Bitronix などの分散トランザクション マネージャーを使用して分散システム全体で使用できます。ただし、このアプローチはお勧めしません。このアプローチには、待ち時間が長くなり、耐障害性が低いため、マイクロサービスのコンテキスト内でいくつかの制限があります。私があなただったら、通常はこのアプローチを避け、Saga パターンを選択するでしょう。

3.イベント駆動型アーキテクチャ: サービスがイベントを通じて通信するイベント駆動型アプローチの使用は、分散トランザクションの処理に特に適しています。このアプローチは、Saga パターンとよく一致します。各サービスはトランザクションを独立して実行し、結果を他のサービスに通知するイベントを発行します。これらのイベントは、Apache Kafka、RabbitMQ、またはその他のメッセージ ブローカーを使用して処理できます。

それでは、これがコードでどのように機能するかを見てみましょう。

サガ パターンにはいくつかの種類がありますが、この記事では、Spring Boot でオーケストレーション ベースのサガ パターンを実装してみます。

ステップ 1: Saga Orchestrator の定義:
ここでは、トランザクションの調整を担当するオーケストレーターとして機能する簡単なサービスを作成します。

このサービスは、各サービスを正しい順序で呼び出し、必要に応じて補正トランザクションを処理するという、物語の流れを定義します。

@Service
public class OrderSagaOrchestrator {

    @Autowired
    private PaymentService paymentService;

    @Autowired
    private InventoryService inventoryService;

    @Autowired
    private ShippingService shippingService;

    public void createOrderSaga(Order order) {
        try {
            paymentService.processPayment(order.getPaymentDetails());
            inventoryService.reserveInventory(order.getItems());
            shippingService.initiateShipping(order.getShippingDetails());
        } catch (Exception e) {
            // Compensation logic
            shippingService.cancelShipping(order.getShippingId());
            inventoryService.releaseInventory(order.getItems());
            paymentService.refund(order.getPaymentId());
        }
    }
}
ログイン後にコピー
ログイン後にコピー

ステップ 2: 各サービスでのローカル トランザクションと報酬メソッドの作成:

各サービスには、物語のステップを完了するためのトランザクションと、必要に応じてそれを補うためのトランザクションが必要です。これがどのように見えるかの一般的な構造です。

@Service
public class PaymentService {

    @Transactional
    public void processPayment(PaymentDetails details) {
        // Perform payment logic
    }

    @Transactional
    public void refund(String paymentId) {
        // Perform refund logic
    }
}
ログイン後にコピー

ステップ 3: イベントベースの通信 (オプション、コレオグラフィー用): 各サービスはイベントを発行して、トランザクションの結果を他のサービスに通知できます。

public class PaymentService {

    private final ApplicationEventPublisher eventPublisher;

    public PaymentService(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }

    public void processPayment(PaymentDetails details) {
        // Process payment
        eventPublisher.publishEvent(new PaymentProcessedEvent(this, details));
    }
}
ログイン後にコピー

ステップ 4: データの一貫性を保証するための手順を実行します: 冪等性チェックを使用して、サガの各ステップが 1 回だけ実行されるようにします。これは、ネットワーク障害や再試行がリクエストの重複につながる可能性がある分散システムでは重要です。

ステップ 5: 信頼性を高めるためにメッセージ ブローカーを使用する: イベントを使用してサガを管理している場合は、RabbitMq の Kafka のようなメッセージ ブローカーが提供します。耐久性があり、サービスが一時的に利用できない場合にイベントをバッファリングできます。

ステップ 6: エラー処理と再試行: オーケストレーターと個々のサービスにエラー処理と再試行のロジックを組み込み、一時的な障害を処理します。 Spring Retry は、構成可能なポリシー内で失敗した操作を自動的に再試行できるため、ここで役立ちます。

@Service
public class OrderSagaOrchestrator {

    @Autowired
    private PaymentService paymentService;

    @Autowired
    private InventoryService inventoryService;

    @Autowired
    private ShippingService shippingService;

    public void createOrderSaga(Order order) {
        try {
            paymentService.processPayment(order.getPaymentDetails());
            inventoryService.reserveInventory(order.getItems());
            shippingService.initiateShipping(order.getShippingDetails());
        } catch (Exception e) {
            // Compensation logic
            shippingService.cancelShipping(order.getShippingId());
            inventoryService.releaseInventory(order.getItems());
            paymentService.refund(order.getPaymentId());
        }
    }
}
ログイン後にコピー
ログイン後にコピー

結論

マイクロサービスでの分散トランザクションは困難ですが、Saga のようなパターン (特にオーケストレーションを使用した場合) やイベント駆動型の通信を使用することで、信頼性が高くスケーラブルなソリューションを実現できます。

Spring Boot は、トランザクション管理、イベント発行、メッセージ ブローカーとの統合のサポートを提供することで、これを容易にします。

最終的に、この調整された物語により、アリスのエクスペリエンスはスムーズかつ一貫したものになり、問題が発生した場合でも、システムの整合性を維持する方法で解決されます。これは、マイクロサービスにおける分散トランザクションと補償ロジックの魔法です。

以上が複数のサービスにわたるトランザクション操作。狂気へのメソッド。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート