MQ トランザクション メッセージを使用して分散トランザクションを実現する

MQ トランザクション メッセージの使用シナリオ

メッセージ キュー内の「トランザクション」は、主にメッセージ プロデューサとメッセージ コンシューマの間のデータの一貫性の問題を解決します。
私たちがよく知っている電子商取引を例に考えてみましょう。一般に、ユーザーが電子商取引アプリで買い物をするときは、まず商品をショッピング カートに追加し、次に複数の商品をまとめて注文し、最後に支払いを行って買い物プロセスを完了し、配達を待つことができます。 。
このプロセスには、メッセージ キューの使用を必要とするステップがあり、注文システムは注文を作成した後、ショッピング カート システムにメッセージを送信して、注文された商品をショッピング カートから削除します。注文した商品をショッピング カートから削除するステップは、ユーザーが注文して支払うというメイン プロセスでは必須のステップではないため、メッセージ キューを使用してショッピング カートを非同期にクリーンアップする方が合理的です。

ここに画像の説明を挿入

注文システムの場合、実際には注文作成プロセスで 2 つのステップが実行されます:
1 注文データを注文ライブラリに挿入して注文を作成します;
2 メッセージをメッセージ キューに送信します。メッセージの内容は注文です。作成したばかりです。

ショッピング カート システムは、対応するトピックをサブスクライブし、注文作成のメッセージを受信した後、ショッピング カートをクリーンアップして、ショッピング カート内の注文の品目を削除します。

分散システムでは、上記の手順のいずれかが失敗する可能性があります。処理が行われない場合、注文データとショッピング カート データの間に不一致が生じる可能性があります。ショッピング カートをクリアします。注文は正常に作成されませんでしたが、
アイテム
はショッピングカートが空になりました。

解決すべき問題は次のように要約できます。上記の手順のいずれかが失敗した場合に備えて、注文ライブラリとショッピング ガレージの 2 つのライブラリのデータの整合性も確保する必要があります。

ショッピング カート システムが注文作成成功メッセージを受信した後のショッピング カートのクリーニング操作については、ショッピング カートが正常にクリーンアップされ、消費確認を送信できる限り、失敗の処理は比較的簡単です。消費確認が送信されていないため、メッセージ キューは自動的に再試行されます。

問題の重要な点は注文システムです。注文の作成とメッセージの送信という 2 つの手順が成功するか、両方とも失敗するかのどちらかです。一方が成功し、もう一方が失敗することは許されません。
これはトランザクションが解決する必要がある問題です。

メッセージキューは分散トランザクションをどのように実装しますか?

トランザクション メッセージを実現するには、メッセージ キューが提供する対応する機能が必要であり、Kafka と RocketMQ の両方がトランザクション関連の機能を提供します。

注文とカートの例に戻ります。

ここに画像の説明を挿入
まず、注文システムはメッセージ キューでトランザクションを開始します。次に、注文システムはメッセージ サーバーに「ハーフ メッセージ」を送信します。このハーフ メッセージは、メッセージの内容が不完全であることを意味するのではなく、そこに含まれる内容は完全なメッセージの内容です。または、メッセージは表示されません。

ハーフメッセージが正常に送信された後、注文システムはローカルトランザクションを実行し、注文ライブラリに注文レコードを作成し、注文ライブラリのデータベーストランザクションを送信できます。次に、ローカルトランザクションの実行結果に応じて、トランザクションメッセージをコミットするかロールバックするかを決定します。注文が正常に作成された場合は、トランザクション メッセージを送信すると、ショッピング カート システムはこのメッセージを使用して後続のプロセスを続行できます。注文の作成が失敗した場合、トランザクション メッセージはロールバックされ、ショッピング カート システムはメッセージを受信しません。このようにして、「すべて成功するか、両方とも失敗するか」という一貫性要件が基本的に実現されます。

この実装プロセスでは、まだ解決されていない問題があります。4 番目のステップでトランザクション メッセージのコミットに失敗した場合はどうなりますか? この問題に対して、Kafka と RocketMQ は 2 つの異なる解決策を提供します。

Kafka のソリューションは比較的単純かつ失礼で、例外を直接スローし、ユーザーが自分で処理できるようにします。送信が成功するまでビジネス コードで繰り返し送信を再試行するか、以前に作成した注文を削除して補正することができます。RocketMQ は別のソリューションを提供します

RocketMQ での分散トランザクションの実装

RocketMQ のトランザクション実装では、トランザクション メッセージの送信失敗の問題を解決するために、トランザクション リバース チェック メカニズムが追加されています。プロデューサーが注文システムであり、トランザクション メッセージが送信またはロールバックされるときにネットワーク例外が発生し、RocketMQ のブローカーが送信またはロールバックのリクエストを受信しない場合、ブローカーは、対応するローカル トランザクションのステータスを定期的にチェックします。プロデューサー上のトランザクションに送信し、リバースチェックの結果に従って、トランザクションをコミットするかロールバックするかを決定します。

このトランザクション アンチチェック メカニズムをサポートするには、ビジネス コードで、ローカル トランザクションが成功したか失敗したかを RocketMQ に通知するアンチチェック ローカル トランザクション ステータスのインターフェイスを実装する必要があります。

この例では、ローカル トランザクションをバックチェックするロジックも非常に単純です。メッセージ内の注文 ID に従って注文ライブラリに注文が存在するかどうかを確認するだけです。注文が存在する場合は成功を返し、存在しない場合は成功を返します。失敗を返します。
RocketMQ は、トランザクション リバース チェックの結果に従って、トランザクション メッセージを自動的にコミットまたはロールバックします。

このアンチチェック ローカル トランザクションの実現は、メッセージの送信者、つまり注文サービスのインスタンス ノード上のデータには依存しません。この場合、トランザクション メッセージを送信した注文サービス ノードがダウンしている場合でも、RocketMQ は他の注文サービス ノードを通じて逆方向チェックを実行して、トランザクションの整合性を確保できます。
前述の一般的なトランザクション メッセージの実装と RocketMQ のトランザクション アンチチェック メカニズムに基づいて、RocketMQ トランザクション メッセージ機能を使用して分散トランザクションを実現するプロセスは次のとおりです。
ここに画像の説明を挿入

多くの人がよく疑問に思うことがあります。注文データをメッセージ キューに送信する前に、注文が正常に作成されるのを待ってみてはどうでしょうか? このようにすると、オーダーの作成に失敗してメッセージが送信される状況を考慮する必要がなくなります。

注文が先に作成された場合、不可抗力な要因により現在のサービスが正常に動作せず、ショッピング カート システムにメッセージが送信されない場合、注文は作成され、ショッピング カートは空になっていません。
ハーフメッセージを送信する場合、トランザクションのステータスを定期的にクエリし、特定のビジネスに応じて操作をロールバックするか、メッセージを再送信して、データの最終的な整合性を確保できます

コード実装と基礎となるコード原則: RocketMQ ソース コード分析 9.3 9.4 9.5

おすすめ

転載: blog.csdn.net/lx9876lx/article/details/130574301