RabbitMQを使用して分散トランザクションの問題を解決するにはどうすればよいですか

序文

以前のb2cプロジェクトを振り返ると、注文サービスエリアでは、分散トランザクションの問題が関係しています。シナリオは次のとおりです。注文が送信されると、注文を作成し、リモート在庫サービスを呼び出して在庫をロックし、支払いまで待つ必要があります。成功すると、ロックされたインベントリが削減されます。リモートコールに関しては、2つのトランザクションの状態に不整合がある可能性があります。

ローカルトランザクションと分散トランザクション

簡単に言えば

ローカルトランザクション:サービス内の
トランザクションです分散トランザクション:マイクロサービスでは、複数のサービス間の呼び出しが含まれます。現時点では、複数のサービスでトランザクションの一貫性を維持する必要があります。これは分散トランザクションのカテゴリです。アップ。

地方事情

地方問題の関連する知識ポイントを確認しましょう:問題
の特徴:(ACID)

  • A:アトミシティ、つまり、トランザクション内のすべての操作が正常に実行されるか、すべて失敗します
  • C:一貫性、つまり、トランザクションの前後の操作の全体的なデータに一貫性がある
  • I:分離、つまり、トランザクションとトランザクション操作は相互に影響しません
  • D:永続性。つまり、トランザクションが完了すると、永続的なストレージとしてディスクに永続化され、失われることはありません。

トランザクションの分離レベル:

セットアップ 説明
シリアル化可能 ダーティ読み取り、繰り返し不可能な読み取り、および仮想読み取りの発生を回避できます。(シリアル化)
繰り返し読み取り ダーティ読み取りと繰り返し不可能な読み取りの発生を回避できます。(繰り返し読むことができます)
コミット済みを読む ダーティリードの発生を回避できます(リードが送信されました)。
コミットされていない読み取り 最低レベル、上記の条件のいずれも保証できません。(コミットされていないものを読む)

トランザクションの伝播形式は次のとおりです
。Springでは、@ Transactional(propagation = Propagation.REQUIRED)がトランザクションの伝播レベルを設定します。これは、内部メソッドが呼び出されると、トランザクション
ここに写真の説明を挿入
共有されることを意味します。次に、新しいトランザクションを作成します。
ただし、トランザクションの共有にはバグがあります。つまり、Springはトランザクションの処理時にプロキシメソッドを使用するため、メソッドを呼び出すときは、このプロキシクラスを経由する必要があります。そうでない場合、トランザクションではありません。

分散トランザクション

なぜ分散トランザクションがあるのですか?
マイクロサービスモジュールでは、複数のサービス間でリモートコールを行うのが一般的であり、それを使用すると、多くの場合、例外が発生します:マシンのダウンタイム、ネットワークの異常、メッセージの損失、メッセージの乱れ、データエラー、信頼性の欠如現時点では、TCP、ストレージデータの損失など、グローバルトランザクションの一貫性を確保するために分散トランザクションが必要です。
CAP理論とBASE理論
CAP:

  • C:データの一貫性
  • A:クラスターの可用性
  • P:パーティションの耐障害性
    は、これら3つのポイントのうち最大で2つしか達成できず、3つが両方を持つことはできません。通常、パーティションの耐障害性を確保する必要があり、C / Aは状況によって異なります。
    ベース:
  • BA:基本的に利用可能:分散システムで障害が発生すると、応答時間や機能の可用性など、可用性の一部が失われる可能性があります
  • S:ソフト状態:システムが中間状態を持つことを許可します。これは、システムの可用性に影響を与えません。
  • E:最終的な一貫性:システム内のすべてのデータコピーが一定期間後に一貫した状態に到達できることを意味します。

分散トランザクションソリューション:

  • 2PCモード:トータルトランザクション管理、複数のローカルリソースマネージャー。データを更新する場合、トランザクションマネージャは最初にデータを送信する準備ができているメッセージを送信し、各リソースマネージャは確認を送り返します。誰もいない限り、このデータ操作のトランザクションは実行できません。
  • 柔軟なトランザクション-TCC:トランザクションがロールバックされると、復元されたデータはログを介してロールバックされます。(これは不確かです。後で詳しく説明します)
  • 柔軟なトランザクション信頼性のあるメッセージ+最終的な整合性ソリューション(非同期保証タイプ)。私のプロジェクトのソリューションは、ビジネスが処理された後、トランザクションが送信される前にファクトメッセージサービスにメッセージを送信するというものです。リアルタイムサービスは、メッセージデータのみを記録し、実際には送信していません。トランザクションが送信された後、ビジネスサービスはリアルタイムメッセージサービスへの送信を確認します。リアルタイムメッセージサービスは、確認送信命令を受信した後にのみ送信します。

プロジェクトソリューション

注文送信プロセス:

RabbitMQ遅延キュー(タイミングタスクの実装)

遅延キューは、メッセージTTLとデッドレター交換を使用して実現できます。
メッセージTTLとは何ですか。メッセージの存続時間は、
デッドレターエクスチェンジとは何ですか?メッセージが条件を満たした後、デッドレタールーティングに入ります。実際、ここでのデッドレター交換は通常の交換と同じです。メッセージが特定のデッドレター交換キューのセットで期限切れになると、メッセージの転送が自動的にトリガーされるだけです。このスイッチに転送します。
これにより、遅延キューが実装されます。
私の考えは、[注文の送信]ボタンをクリックしてからリクエストを送信し、注文を作成することです。注文が正常に作成されたら、MQにメッセージを送信し、リモートでインベントリをロックします。インベントリがロックされたら、インベントリサービスの下でMQにメッセージを送信します。残りは監視中です。30分後に在庫ロックメッセージの有効期限が切れます。在庫のロックを解除するメッセージを受信した後、在庫を解放します。しばらくすると、注文メッセージの有効期限が切れ、注文終了メッセージを受信したので、ロックを解除します。在庫
次に、どのような状況で在庫のロックを解除する必要があるかを明確にする必要があり
ます。在庫のロックメッセージの有効期限が切れたというメッセージが表示されます。このメッセージには、作業指示ID、在庫のロックの詳細が含まれます。作業指示IDから注文番号を取得し、注文モジュールをリモートで呼び出して、注文が存在するかどうかを確認できますか?注文が存在しない場合は、在庫のロックを解除する必要があります。存在する場合は、注文のステータスを確認する必要があります。キャンセルされた状態で在庫のロックを解除する必要があります。有料のものはロックを解除する必要はありません。ロックを解除する過程で、ロックインベントリ詳細テーブルのロックステータスも確認する必要があります。インベントリがロック解除されている場合は、ロックを解除する必要はなく、ロック状態をロック解除する必要があります。
また、注文の有効期限が切れて支払いが行われていない場合は、このメッセージを監視する必要があります。また、ロックを解除する必要があります。
ただし、上記の考え方にはまだ問題があります。注文のロックを解除する場合、ネットワークの遅延などの条件により、注文のロックが解除される前に在庫のロックが解除され、注文の在庫情報の一部が失われ、ロックを解除できなくなります。この場合、在庫サービスで注文終了メッセージも聞きました。注文終了メッセージを受信した後、在庫のロックを解除し、次に在庫のロック解除された在庫のロックを解除しました。
上記のメッセージの有効期限が切れたときに採用した戦略には、次のようなものがあります。注文の有効期限が切れたときに支払われていないメッセージを消費し、注文のサービスオペレーションを閉じ、在庫サービスの有効期限が切れた後、または注文ステータスがキャンセルされた後、注文が見つからないというメッセージを実行します。最終的には、この状況を回避することも保証されます。注文サービスがスタックするのを防ぎます。これにより、注文ステータスメッセージが変更できないままになり、在庫の優先度が期限切れになり、注文ステータスが新しく作成され、何も処理されないため、注文がスタックします。在庫の問題のロックを解除することはできません。

最終的な一貫性を解決した後、メッセージの信頼性を確保するにはどうすればよいですか?

ニュースは信頼できず、すべての操作はクラウドです。ネットワーク上でメッセージを送信しているときにメッセージが失われた場合はどうなりますか?メッセージが失われる主な理由は次のとおりです。

  • メッセージは送信されましたが、ネットワーク上の理由によりサーバーに到達しませんでした。この状況は避けられません。ログ情報をデータベースに保存する必要があります。設計が失敗した後、再送信メカニズムがあり、これらの失敗したメッセージについてデータベースを定期的にスキャンします。 。
  • メッセージがブローカーに到着すると、ブローカーは成功したと見なされるためにメッセージをディスクに永続化する必要があります。永続化が成功しなかった場合、ブローカーはダウンし、メッセージは失われます。この時点で、パブリッシャーが成功したメッセージを確認するためのコールバックメカニズムを確認する必要があります。データベースメッセージのステータスを変更します。
  • 自動ACK状態では、消費者はメッセージを受信しますが、応答を確認する時間がありません。マシンがダウンしている場合、メッセージは失われます。このとき、メッセージを正常に削除するには、手動ackをオンにする必要があります。そうしないと、メッセージはキューに戻ります。

メッセージの繰り返しについては、データベースにアンチウェイトテーブルを設計するか、操作されていない情報のみを消費するか、またはビジネスで独立するように設計することができます。

メッセージバックログの場合:より多くの消費者とオンラインに接続できます。メッセージの処理専用のキューを使用してオンラインに接続し、これらのメッセージを監視してデータにまとめて保存し、オフラインプログラムのデータベースでこれらのメッセージを処理することもできます。

総括する

要するに、その過程で非常に難しいのです。いろいろな状況を考える必要があります。こういうことで問題があるかもしれません。ゆっくりと経験を積む必要があります。データベースに問い合わせるには、キャッシュデータの不整合の問題を解決し、システムスループットを向上させるために、キャッシュを追加します。データベースメッセージの変更には注意する必要があります。

おすすめ

転載: blog.csdn.net/MarkusZhang/article/details/107928595