記事ディレクトリ
メッセージキューはトランザクションの問題を解決します
トランザクションを解決するためにメッセージ キューが使用される場合、メッセージはどの段階で MQ に送信されますか?
-
金額を差し引いてから
RocketMQ にメッセージを送信 金額を差し引いてからメッセージを送信 メッセージの送信がタイムアウトすると(MQ では成功する場合と失敗する場合があります)、状態の判断が難しくなります。 -
最初に RocketMQ にメッセージを送信してから
お金を差し引きます。引き落とし成功メッセージは正常に送信されますが、ローカルの差し引きビジネスが失敗した場合、メッセージは MQ に送信され、お金を追加する 2 番目のフェーズが正常に実行されます。
したがって、どのソリューションを採用しても、その処理には問題が発生します。
実際、注意深く分析した結果、この問題の重要な点は、RocketMQ がメッセージ送信者のトランザクション ステータスを変更できないことです。したがって、RocketMQ の分散トランザクション ソリューションは最適化されています。
RocketMQ の分散トランザクション ソリューション
RocketMQ は、分散トランザクションにセミトランザクションおよびトランザクション レビュー メカニズムを導入します。
セミトランザクション:
メッセージを rocketmq に送信します。ただし、メッセージは commitlog に保存されるだけで、consumeQueue には表示されません。つまり、コンシューマー (サブスクライバー) はメッセージを表示できません。
取引レビュー:
RocketMq はコミットログ内のセミトランザクション メッセージを定期的に走査します。このトランザクション レビュー メカニズムは、RocketMQ の観点からメッセージ送信者のトランザクションに参加できます。
RocketMQ 分散トランザクションのケース コード
これは分散トランザクションのプロデューサーであり、半分のトランザクションの送信を完了します。
TransactionListenerImpl クラスの useLocalTransaction メソッドでトランザクション レビューを行うと、ローカル トランザクションが正常に実行されると、commit_message が送信され、コンシューマーはメッセージを消費できます。
このステップで確認できない、時間のかかる操作がある場合は、「不明」を送信して、スケジュールされたタスクのレビューに処理を任せることができます。
分散トランザクションのソースコード解析
分散トランザクションのプロセスは、メッセージ送信、確認/ロールバック、レビューの3つの側面から分析できます。
メッセージ送信ソースコード解析
プロデューサー
ブローカ
RocketMQ は Netty を使用してネットワークを処理し、ブローカーがメッセージの書き込みリクエストを受信すると、SendMessageProcessor クラスの processRequest メソッドに入ります。
最後に、DefaultMessageStore クラスに asyncPutMessage メソッドを入力してメッセージを保存します。
図とコードを組み合わせると、トランザクション メッセージが送信されるとき、メッセージが実際に保存されるトピックはシステム トピックであることがわかります: RMQ_SYS_TRANS_HALF_TOPIC
同時に、メッセージには、メッセージの元のトピックに関連する情報とキューが保存されます。
ソースコード解析の確認/ロールバック
プロデューサー
DefaultMQProducerImpl クラスの sendMessageInTransaction メソッド
ブローカ
EndTransactionProcessor クラス
ソースコード分析のバックチェック
プロデューサー
トランザクションのレビュー中、プロデューサーはサーバーとなるため、サービス処理のために登録する必要があります。
DefaultMQProducerImpl クラスの checkTransactionState メソッド
DefaultMQProducerImpl クラスの processTransactionState メソッド
ブローカ
ブローカーが開始されると、クライアントとして機能し、トランザクションのレビューのために定期的にクライアントにアクセスします。
トランザクション レビューは、ブローカーによって開始されるスケジュールされたネットワーク呼び出し (60 秒ごと) であるため、クライアントの開始時に初めてトランザクション レビューが 60 秒間隔である必要はなく、通常は 60 秒未満です (トランザクション レビューが開始されるため)ブローカーによって)、クライアントによって定期的に開始されるわけではありません)
要約する
RocketMQ は、主に 2 フェーズ コミット プロトコルを通じて分散トランザクションをサポートします。最初のフェーズでは、システムは準備されたメッセージを MQ に送信します。準備されたメッセージの送信に失敗した場合、操作は直接キャンセルされ、実行されません。メッセージの送信が成功した場合は、ローカル トランザクション (executeLocalTransaction) を実行します。成功した場合は、確認メッセージを送信するように MQ に指示し、失敗した場合は、ロールバック メッセージを送信するように MQ に指示します。第 2 フェーズでは、確認メッセージが送信されると、システム B は確認メッセージを受信し、ローカル トランザクションを実行します。確認メッセージまたはロールバック メッセージの送信に失敗した場合、ブローカーには、一意の ID に基づいてローカル トランザクションのステータスを問い合わせるポーリング メカニズムが備わっています。MQ は、準備されたすべてのメッセージを定期的に自動的にポーリングし、インターフェイス (checkLocalTransaction) をコールバックして、メッセージはローカルです。トランザクション処理に失敗しました。確認されていないすべてのメッセージについて、再試行を続行するか、それともロールバックする必要がありますか?