Java Spring Bootの分散トランザクションの問題を解決する方法

PHPz
リリース: 2023-04-18 12:34:02
転載
1543 人が閲覧しました

1. 逆補償とは

まずは用語について説明させていただきますが、分散型取引に関する情報を見ているとよく目にする用語が「逆補償#」です。 ##。逆補償とは何ですか?

例を示します: 今、3 つのマイクロサービス A、B、C があるとします。ここで、A サービスで B サービスと C サービスをそれぞれ呼び出します。B と C が成功するか失敗するかを確認するには、同時に、分散トランザクションも必要になります。しかし、ローカル トランザクションに関するこれまでの理解によれば、B と C のローカル トランザクションの場合、サービス B のトランザクションが完了して送信された後、サービス C のトランザクションには例外が発生し、ロールバックする必要があります。ただし、B はすでにロールバックされています。ロールバックするにはどうすればよいですか?

今回話しているロールバックは、従来の意味での、MySQL REDO ログを介したロールバックのようなものではありません。

SQL の更新と、その後の B サービスの変更によるロールバックです。データ復旧です。

これを逆補償と呼びます。

2. 基本概念のレビュー

Seata には 3 つの中心概念があります:

  • TC (トランザクション コーディネーター) - トランザクション調整作成者: グローバルおよびブランチ トランザクションのステータスを維持し、グローバル トランザクションの送信またはロールバックを推進します。

  • TM (トランザクション マネージャー) - トランザクション マネージャー: グローバル トランザクションのスコープを定義し、グローバル トランザクションを開始し、グローバル トランザクションをコミットまたはロールバックします。

  • RM (リソース マネージャー) - リソース マネージャー: ブランチ トランザクション処理のリソース (リソース) を管理し、TC と通信してブランチ トランザクションを登録し、ブランチ トランザクションのステータスを報告し、ブランチを駆動します。トランザクションのコミットまたはロールバック。

このうち、TC は個別にデプロイされるサーバー、TM と RM はアプリケーションに組み込まれたクライアントです。

次の図を見てみましょう:

Java Spring Bootの分散トランザクションの問題を解決する方法

この図は、基本的にこれら 3 つの概念を明確に説明しています。

実際、この図を見なくても、分散トランザクションの実装原理はおそらく推測できます。まず、グローバル トランザクション コーディネーター (TC) が存在する必要があり、各ローカル トランザクション (RM) が実行を開始します。実行プロセスは、そのステータスをグローバル トランザクション コーディネーターに速やかに報告します。このグローバル トランザクション コーディネーターは、各ブランチ トランザクションの現在の実行ステータスを知っています。彼 (TC) は、すべてのローカル トランザクションが正常に実行されたことを確認すると、全員に一緒にコミットするように通知します。 ; 誰かがこのトランザクションの実行に失敗したことを発見すると、全員に一緒にロールバックするように通知します (もちろん、このロールバックは必ずしも真のロールバックではなく、逆補償です)。では、トランザクションはいつ開始され、いつ終了するのでしょうか?つまり、トランザクションの境界はどこにあるのでしょうか? Seata の分散トランザクションは、

@GlobalTransactional アノテーションによって実装されます。つまり、このアノテーションはどこに追加する必要がありますか?このアノテーションを追加する場所は、実際にはトランザクション マネージャー TM です。

上記の紹介の後、友人は、 Seata を使用して分散トランザクションを実装することは想像されているほど難しくなく、原理は依然として非常に簡単であることを理解するはずです。

Seata には 4 つの異なるモードが含まれます。次に紹介する 4 つの異なるモードは、実際には、ローカル トランザクションが失敗したときにロールバックする方法について話しています。これらは、後で説明する 4 つの異なる分散トランザクション モードです。

3. 2 段階提出とは何ですか

まず次の図をご覧ください:

Java Spring Bootの分散トランザクションの問題を解決する方法

# #この図には 3 つの概念が含まれています:

  • AP:

    言うまでもなく、AP はアプリケーションそのものです。

  • RM:

    RM は、トランザクションの参加者であるリソース マネージャーです。ほとんどの場合、データベースを指します。分散トランザクションには、複数のトランザクションが関与することがよくあります。 RM。

  • TM:

    TM は、分散トランザクションを作成し、分散トランザクション内の各サブトランザクションの実行とステータスを調整するトランザクション マネージャーです。 RM 上で実行される特定の操作に適用されます。

  • では、2 フェーズ コミット (略して 2PC) 送信とは何でしょうか?

2 段階提出の真実は非常に単純です。ソング兄弟は、2 段階提出について説明する簡単な例を挙げます:

たとえば、次の図:

#Business では、それぞれ Storage、Order、Account と呼んでいますが、この 3 つの操作は同時に成功するか失敗する必要があります。異なるサービスでは、最初にこれら 3 つのサービスの操作を個別に実行させ、3 つのサービスのトランザクションを個別に実行させることができます。これが 2 つのフェーズのうちの第 1 フェーズです。 Java Spring Bootの分散トランザクションの問題を解決する方法

実行の最初のフェーズが完了したら、3 つのサービスの一部が実行に失敗している可能性があるため、急いで送信しないでください。この時点で、3 つのサービスは最初のフェーズの実行結果を報告する必要があります。トランザクション コーディネーターがメッセージを受信した後、3 つのサービスの最初のフェーズが正常に実行された場合、3 つのトランザクションはそれぞれ送信するように通知されます。3 つのサービスのいずれかの実行が失敗した場合、3 つのトランザクションは送信されます。現時点では通知されます。個別にロールバックしてください。

これはいわゆる 2 フェーズ コミットです。

要約: 2 フェーズ送信では、トランザクションは参加者 (上図の各特定サービスなど) とコーディネーターに分割されます。参加者は操作の成功または失敗をコーディネーターに通知します。 , その後、コーディネーターはすべての参加者の結果に基づいて操作の成功または失敗を決定します。フィードバック情報により、各参加者が操作を送信するか操作を中止するかが決定されます。ここでの参加者は RM として理解でき、コーディネーターはコーディネーターです。 TM として理解できます。

ただし、Seata のさまざまな分散トランザクション モードは、基本的に 2 フェーズの送信に基づいて進化しているため、まったく同じではありません。

4. AT モード

AT モードは、完全に自動のトランザクション ロールバック モードです。

全体として、AT モードは 2 フェーズ コミット プロトコルを進化させたものです。

  • 1 フェーズ: ビジネス データとロールバック ログ レコードが同じローカル トランザクションで送信されます。 , ローカルのロックと接続リソースを解放します。

  • 第 2 フェーズは 2 つの状況に分かれています: 2.1 非同期で送信します。これは非常に早く完了します。 2.2 ロールバックは、1 段階のロールバック ログを通じて逆補償を実行します。

一般的なロジックは上記のとおりです。特定のケースを通じて AT モードがどのように機能するかを見てみましょう:

次のようなビジネス テーブル製品があると仮定します。次のとおりです:

Java Spring Bootの分散トランザクションの問題を解決する方法

次に、次の更新操作を実行します:

update product set name = 'GTS' where name = 'TXC';
ログイン後にコピー

手順は次のとおりです。次のとおりです:

第一段階:

  • SQL の解析: SQL タイプ (UPDATE)、テーブル (プロダクト)、条件 (ここで、name = 'TXC') およびその他の関連情報。

  • クエリ前のイメージ: 解析で得られた条件情報をもとにクエリ文を生成し、データを検索します(更新前のデータを検索します)。

  • 上記の更新SQLを実行します。

  • ミラー後のクエリ: ミラー前の結果に基づいて、主キーを通じてデータを見つけます。

  • ロールバック ログの挿入: 前後のミラー データとビジネス SQL 関連の情報をロールバック ログ レコードに結合し、UNDO_LOG テーブルに挿入します。

  • 送信する前に、ブランチを TC に登録します。製品テーブル内の主キー値が 1 に等しいレコードのグローバル ロックを適用します。

  • ローカル トランザクションの送信: ビジネス データの更新は、前の手順で生成された UNDO ログとともに送信されます。

  • ローカル トランザクションの送信結果を TC に報告します。

第 2 フェーズ:

第 2 フェーズは、コミットまたはロールバックの 2 つの状況に分かれています。

最初にロールバック手順を見てみましょう:

  • まず、TC からブランチ ロールバック リクエストを受信し、ローカル トランザクションを開始して、次の操作。

  • XID とブランチ ID を使用して、対応する UNDO LOG レコードを検索します (このレコードには、データ変更の前後の対応するイメージが保存されます)。

  • データ検証: UNDO LOG のポストイメージと現在のデータを比較します。差異がある場合は、データが現在のグローバル以外のアクションによって変更されたことを意味します。取引。この状況は、構成ポリシーに従って処理する必要があります。

  • 前のイメージの関連情報と UNDO LOG のビジネス SQL に基づいてロールバック ステートメントを生成して実行します: update product set name = 'TXC' where id = 1;

  • ローカル トランザクションをコミットします。そして、ローカルトランザクションの実行結果(ブランチトランザクションのロールバック結果)をTCに報告します。

送信手順を見てみましょう:

  • TC からブランチ送信リクエストを受け取り、そのリクエストを非同期タスクキューを作成し、成功した送信の結果をすぐに TC に返します。

  • 非同期タスクフェーズでのブランチ送信リクエストは、対応する UNDO LOG レコードを非同期かつバッチで削除します。

これはほぼ同じステップです。概念は比較的明確です。レコードを更新する場合、システムはレコードの更新の前後にコンテンツの JSON を生成します。そして、それをアンドゥログテーブルに保存します。将来ロールバックしたい場合は、アンドゥログの記録に従ってデータを更新(逆補正)します。将来ロールバックしたくない場合は、データを削除してください。アンドゥログに記録されます。

プロセス全体で、開発者は追加の UNDO ログ テーブルを作成し、グローバル トランザクションを処理する必要がある箇所に @GlobalTransactional アノテーションを追加するだけで済みます。

その他の送信、ロールバック、ロールバックはすべて完全に自動で行われるため、簡単に実行できます。そのため、プロジェクトで分散トランザクションを処理するために Seata を使用することを選択した場合でも、AT モードを使用する可能性は依然として非常に高くなります。

5. TCC モード

TCC (Try-confirm-Cancel) モードは、少しマニュアル感があり、2 段階ですが、AT とは異なります。見てください、プロセス。

公式サイトに TCC のフローチャートがありますので見てみましょう:

Java Spring Bootの分散トランザクションの問題を解決する方法

ご覧のとおり、TCC はこれも 2 つの段階に分かれています:

  • 最初の段階は準備です。この段階では主に銀行振込などのリソースの検出と予約が行われます。この段階では、まずユーザーの資金が十分であるかどうかを確認します。足りなければそのまま捨てますが、異常であればまず冷凍して十分です。

  • 第 2 段階はコミットまたはロールバックです。これは主に、各ブランチ トランザクションの最初の段階が完了するのを待ちます。すべての実行が完了すると、それぞれが独自の状況をレポートします。 TC と TC は統計を作成し、TC が各ブランチ トランザクションに例外がないと判断した場合は全員にまとめて送信するよう通知し、TC がブランチ トランザクションが異常であると判断した場合は全員にロールバックするよう通知します。

そして、あなたの友人も、上記のプロセスには準備、コミット、ロールバックという合計 3 つのメソッドが含まれていることを発見したかもしれません。これら 3 つのメソッドは完全にユーザー定義のメソッドです。自分たちで実装するので、最初から TCC は手動モードであると言いました。

AT と比較すると、TCC モードは実際には基盤となるデータベースのトランザクション サポートに依存していないことがわかりました。つまり、基盤となるデータベースがトランザクションをサポートしていなくても問題ありません。とにかく、準備を整えます。 、commit、rollbackの3つすべてのメソッドは開発者自身が記述したものなので、この3つのメソッドに対応する処理をスムーズにすればよいのです。

6.

XA 仕様は、X/Open 組織によって定義された分散トランザクション処理 (DTP、分散トランザクション処理) 標準です。

XA 仕様では、グローバル トランザクション マネージャーとローカル リソース マネージャー間のインターフェイスについて説明します。 XA 仕様の目的は、複数のリソース (データベース、アプリケーション サーバー、メッセージ キューなど) に同じトランザクションでアクセスできるようにし、

ACID

プロパティがアプリケーション間で有効なままになるようにすることです。 XA 仕様では、2 フェーズ コミットを使用して、すべてのリソースが特定のトランザクションを同時にコミットまたはロールバックすることを保証します。

XA 仕様は 1990 年代初頭に提案されました。現在、ほとんどすべての主流データベースが XA 仕様のサポートを提供しています。

XA トランザクションは、2 フェーズ コミット プロトコルに基づいています。すべてのトランザクション参加者が準備作業 (第 1 フェーズ) を完了していることを確認するには、トランザクション コーディネーターが必要です。コーディネーターは、すべての参加者が準備ができているというメッセージを受信すると、すべてのトランザクションをコミットできることを通知します (フェーズ 2)。 MySQL は、コーディネーター (トランザクション マネージャー) ではなく、この XA トランザクションの参加者の役割を果たします。

MySQL の XA トランザクションは、内部 XA と外部 XA に分かれています。外部 XA は外部分散トランザクションに参加でき、アプリケーション層がコーディネーターとして介入する必要があります。内部 XA トランザクションは、Binlog をコーディネーターとして、同じインスタンスの下でクロスエンジン トランザクションに使用されます。たとえば、ストレージ エンジンがコミットすると、情報は分散内部 XA トランザクションであるバイナリ ログに書き込まれます。ただし、バイナリ ログの参加者が MySQL 自体である点が異なります。 MySQL は、コーディネーターではなく、XA トランザクションの参加者の役割を果たします。

言い換えれば、MySQL は XA 仕様を通じて分散トランザクションを自然に実装できますが、必要なのは一部の外部アプリケーションのサポートのみです。 Seata での XA モードの使用プロセスを見てみましょう。

まずは公式の写真を見てみましょう:

Java Spring Bootの分散トランザクションの問題を解決する方法ご覧のとおり、これも 2 段階です。 submit :

フェーズ 1: ビジネス SQL 操作は XA ブランチで実行されます。XA ブランチが完了した後、XA prepare が実行され、RM のサポートによって永続性が保証されます。 XA プロトコル (つまり、その後の事故によってロールバックが不可能になることはありません)。
  • 第 2 フェーズは 2 つの状況に分かれています: コミットまたはロールバック:
  • ブランチの送信: XA ブランチのコミットの実行
  • ブランチ ロールバック: XA ブランチのロールバックを実行します。
  • 前の 2 つのモードの違いは、XA モードでのロールバックは重大なロールバックであることです。は、逆補償ではなく、従来の意味で理解されているロールバックです。
7. サーガ モード

最後に、サーガ モードについて説明します。このモードはほとんど使用されないため、誰でも理解できます。

saga モードは、seata が提供するロング トランザクション ソリューションですが、ロング トランザクションは効率が悪く、デッドロックが発生しやすいため、開発では避けるべきです。

このサガ モードは、プロセス エンジンに少し似ています。開発者は最初に自分でプロセス エンジンを作成し、トランザクション全体に関与するすべてのメソッドを含めます。各メソッドが何かを返すとき、それは正常であり、それが何であれ、戻り値は 異常の場合、正常の場合は続行 異常の場合、別の処理を実行する つまり、メソッドを 2 セット用意しておく必要があります。最初のセットは実行です

緑のプロセスは通常のプロセス、2 番目のセットは例外のプロセスです。その後の実行プロセスは次のようになります。例外が発生した後にロールバックされるプロセスです。ロールバックも一種の逆補償です。 Java Spring Bootの分散トランザクションの問題を解決する方法

以上がJava Spring Bootの分散トランザクションの問題を解決する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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