ホームページ >Java >&#&面接の質問 >[インタビュー] メッセージを 100% 確実に配信するにはどうすればよいですか?メッセージの冪等性を確保するにはどうすればよいでしょうか?

[インタビュー] メッセージを 100% 確実に配信するにはどうすればよいですか?メッセージの冪等性を確保するにはどうすればよいでしょうか?

Java学习指南
Java学习指南転載
2023-07-26 14:58:33755ブラウズ

#############################################I.はじめに##

# 私たちの友人は、RabbitMQ、RocketMQ、Kafka などのメッセージ ミドルウェア MQ について十分に聞いているはずです。ミドルウェアを導入するメリットは、高い同時実行性、ピーキング、ビジネスの分断に対抗する役割を果たす可能性があります。
上に示すように:

[インタビュー] メッセージを 100% 確実に配信するにはどうすればよいですか?メッセージの冪等性を確保するにはどうすればよいでしょうか? (1) オーダー サービスは MQ ミドルウェアにメッセージを配信します (2) ロジスティクス サービスは消費される MQ ミドルウェア メッセージを監視します

この記事では、RabbitMQ を例として、注文サービスがメッセージを MQ ミドルウェアに確実に正常に配信する方法について説明します。

2. 問題の分析

[インタビュー] メッセージを 100% 確実に配信するにはどうすればよいですか?メッセージの冪等性を確保するにはどうすればよいでしょうか? 友人がこれについて質問するかもしれません。注文サービスがメッセージ サービスを開始し、返信が成功した、それは成功という意味ではないでしょうか?たとえば、次のような疑似コード:


上記のコードでは、一般的に次のようにメッセージが送信されますが、何か問題があると思いますか?

シナリオについて話しましょう。MQ サーバーが突然ダウンしたらどうなりますか?注文サービスから送信されたメッセージはすべて消えてしまったのでしょうか?はい、通常、MQ ミドルウェアはシステムのスループットを向上させるためにメッセージをメモリに保存します。他の処理が行われない場合、MQ サーバーがダウンするとすべてのメッセージが失われます。これはビジネスでは許可されていないため、大きな影響を及ぼします。

3. 永続性 経験豊富な友人は、メッセージを永続化して RabbitMQ でメッセージを送信する方法があると言うでしょう。設定可能な永続パラメータ。true に設定すると永続的になります。

[インタビュー] メッセージを 100% 確実に配信するにはどうすればよいですか?メッセージの冪等性を確保するにはどうすればよいでしょうか?

この場合、MQ サーバーがダウンしても、メッセージは再起動後にディスク ファイルに保存されるため、メッセージは失われません。はい、これにより、メッセージが一定の確率で失われないことが保証されます。

しかし、メッセージが MQ メモリに保存されたばかりで、ディスク ファイルに更新される前に突然クラッシュするというシナリオも考えられます。 (なんと、これは短期間で起こります。確率が低すぎます。) このシナリオは、継続的な大規模メッセージ配信のプロセスでは非常に一般的です。 ######私たちは何をすべきか?ディスクに確実に保存するにはどうすればよいでしょうか?

4. メカニズムの確認上記の問題は、永続化が成功したかどうかを誰も教えてくれないという事実から発生します。幸いなことに、多くの MQ にはコールバック通知機能があり、RabbitMQ には永続化が成功したかどうかを通知する確認メカニズムがあります。

確認メカニズムの原理: [インタビュー] メッセージを 100% 確実に配信するにはどうすればよいですか?メッセージの冪等性を確保するにはどうすればよいでしょうか?


(1) メッセージプロデューサーは MQ にメッセージを送信し、受信が成功すると、MQ は ack を返します。プロデューサーへのメッセージ ;

(2) メッセージの受信が失敗した場合、MQ はプロデューサーに nack メッセージを返します。

上記の疑似コードには、次の 2 つの方法があります。メッセージを処理します。これは、ack コールバックと nack コールバックです。 [インタビュー] メッセージを 100% 確実に配信するにはどうすればよいですか?メッセージの冪等性を確保するにはどうすればよいでしょうか?


これにより、メッセージが 100% 失われないことが保証されますか?

確認メカニズムを見てみましょう。プロデューサがメッセージを送信するたびに、MQ をディスクに永続化し、ack または nack コールバックを開始する必要があると想像してください。この場合、メッセージを毎回ディスクに保存する必要があるため、MQ のスループットは非常に低くなります。ディスクへの書き込みが非常に遅いです。これは同時実行性が高いシナリオでは受け入れられず、スループットが低すぎます。

MQ 永続ディスクの実際の実装は、非同期呼び出しによって処理され、特定のメカニズムがあり、たとえば、数千のメッセージがある場合、一度にディスクにフラッシュされます。メッセージが届くたびにディスクをフラッシュするのではなく。

つまり、comfirm メカニズムは実際には、システムの高スループットを確保するための非同期リスニング メカニズムです。これは、メッセージが失われないことが 100% 保証されていないことを意味します。確認メカニズムが追加されると、メッセージは失われません。メモリがディスクにフラッシュされる前に MQ がクラッシュし、それでも処理できませんでした。

ここまで言いましたが、まだ保証はできません。どうすればよいでしょうか? ? ?

5. 事前にメッセージを永続化する スケジュールされたタスク

実は、本質的な理由は、永続化されているかどうかを判断できないことです。では、メッセージを自分で永続化できるでしょうか?答えは「はい」です。私たちの計画はさらに進化します。

[インタビュー] メッセージを 100% 確実に配信するにはどうすればよいですか?メッセージの冪等性を確保するにはどうすればよいでしょうか?

上の図のプロセス:

(1) 注文サービスプロデューサーがメッセージを配信する前に、メッセージを Redis または DB に永続化する必要があります。パフォーマンスの高い Redis をお勧めします。メッセージのステータスは送信中です。

(2) 確認メカニズム監視メッセージは正常に送信されましたか? ACK が成功した場合は、Redis でこのメッセージを削除します。

(3) nack が失敗した場合、メッセージを再送信するかどうかは、業務に応じて選択できます。ビジネス上の決定に応じて、このメッセージを削除することもできます。

(4) 一定期間後にメッセージをプルするスケジュールされたタスクがここに追加されます。メッセージ ステータスはまだ送信中です。このステータスは、注文サービスが確認応答メッセージを受信して​​いないことを示します。

(5) スケジュールされたタスクは、補償メッセージを配信します。このとき、MQ コールバック ACK が正常に受信されると、Redis 内でメッセージが削除されます。

このようなメカニズムは実際には補償メカニズムです。MQ が実際にそれを受信するかどうかは関係ありません。Redis 内のメッセージのステータスが [送信中] である限り、メッセージが送信されていることを意味します。正しく受信できませんでした。次に、スケジュールされたタスクを開始して、補償の配信を監視および開始します。

もちろん、スケジュールされたタスクに補正番号を追加することもできますが、3 回を超えても ack メッセージが受信されない場合は、メッセージのステータスを直接 [失敗] に設定し、手動でチェックしてください。なぜですか?

この場合、ソリューションは比較的完璧で、メッセージの 100% が失われないことが保証されています (もちろん、ディスク障害は含まれていないため、マスター/スレーブ ソリューションを使用できます)。

ただし、このソリューションでは、同じメッセージを複数回送信することができます。MQ はすでにメッセージを受信して​​いる可能性が非常に高いですが、ack メッセージのコールバック中にネットワーク障害が発生し、プロデューサーはそれを受け取りませんでした。

次に、消費時に冪等性を確保することを消費者に要求する必要があります。

6. べき等性の意味

まず、べき等性とは何かを理解しましょう。分散アプリケーションでは、冪等性、つまり、同じ条件でビジネスを実行すれば、何度実行しても結果は同じであることが非常に重要です。

6.1. 冪等のようなシナリオが存在するのはなぜですか?

なぜ冪等のようなシナリオがあるのでしょうか?大規模なシステムでは、すべてが分散して展開されるため、たとえば、受注業務と在庫業務が独立して別のサービスとして展開される場合があります。ユーザーが注文すると、注文サービスと在庫サービスが呼び出されます。

[インタビュー] メッセージを 100% 確実に配信するにはどうすればよいですか?メッセージの冪等性を確保するにはどうすればよいでしょうか?

分散配置により、インベントリ サービスを呼び出すときに、ネットワークやその他の理由で注文サービスの呼び出しが失敗する可能性が非常に高くなりますが、実際にはインベントリ サービスは処理されており、次の場合にのみ表示されます。処理結果は注文サービスに返されます。例外。この時点で、システムは通常、補償計画を作成します。つまり、注文サービスが在庫サービスを呼び出し、在庫が 1 つ減ります。

[インタビュー] メッセージを 100% 確実に配信するにはどうすればよいですか?メッセージの冪等性を確保するにはどうすればよいでしょうか?

#問題があります。実際、最後の呼び出しは 1 減りましたが、注文サービスは処理結果を受け取っていません。ここで再び呼び出され、1 減らす必要があります。これはビジネスに合致しておらず、追加の控除です。

冪等性の概念は、同じ条件でインベントリ サービスを何度呼び出しても、処理結果は同じになるということです。この方法によってのみ、補償計画の実現可能性が保証されます。

#6.2. オプティミスティック ロック スキーム

次のようなデータベースのオプティミスティック ロック メカニズムから学習します。

#バージョンに基づいて、つまり、インベントリを操作する前に現在の製品のバージョン番号を取得し、操作時にこのバージョン番号を持参します。整理しましょう。初めて在庫を操作したときはバージョン 1 が取得され、在庫サービスを呼び出したときにバージョンは 2 になりました。しかし、注文サービスに戻るときに問題が発生しました。注文サービスは別のサービスを開始しました。在庫サービスへの呼び出し オーダーサービスがバージョン1のままで渡された場合、上記のSQL文を再度実行してもバージョンが2に変わっているため実行されず、where条件が成立しません。これにより、何度呼び出されても、処理されるのは 1 回だけになります。
[インタビュー] メッセージを 100% 確実に配信するにはどうすればよいですか?メッセージの冪等性を確保するにはどうすればよいでしょうか?

6.3. 一意の ID フィンガープリント コード

原則は、データベースの主キーを使用して重複を削除し、その後に主キー ID を挿入することです。ビジネスは完了しました

[インタビュー] メッセージを 100% 確実に配信するにはどうすればよいですか?メッセージの冪等性を確保するにはどうすればよいでしょうか?
一意の ID は、製品 ID などのビジネス テーブルの唯一の主キーです
  • フィンガープリント コードは、通常の操作ごとにコードを区別するためのもので、操作ごとに生成され、タイムスタンプのビジネス番号が使用できます。

  • 上記の SQL ステートメント:

    • 戻り値が 0 の場合、操作が実行されていないことを意味します。ビジネス オペレーションの後で実行できます。 t_check (一意の ID フィンガープリント コード) に挿入します。

    • Return 0 より大きい場合、オペレーションが実行されたことを意味します。

    利点: シンプルな実装

    欠点: 同時実行性が高い場合のデータベースのボトルネック

    解決策: データベースとテーブルを分割するアルゴリズム ルーティングの ID

    6.4、Redis アトミック操作

    Redis のアトミック操作を使用して、操作の完了をマークします。このパフォーマンスの方が優れています。しかし、いくつかの問題もあるでしょう。

    最初: ビジネス結果をデータベースに保存する必要がありますか?その場合、解決すべき重要な問題は、データベースと Redis 操作でアトミック性を実現する方法です?

    これはインベントリが 1 減少することを意味しますが、redis 操作がマークを完了するときに失敗した場合はどうすればよいでしょうか?つまり、データベースの削除と redis が同時に成功するか失敗するかを確認する必要があります。

    2 番目: データベースが削除されない場合、両方ともキャッシュに保存されます。同期戦略?

    これは、インベントリが 1 減り、インベントリは削除されないことを意味します。Redis 操作を直接実行してマーキングを完了し、別の同期サービスを使用してインベントリを削除します。これは、システムと同期戦略の複雑さが増します。セットアップ方法

    以上が[インタビュー] メッセージを 100% 確実に配信するにはどうすればよいですか?メッセージの冪等性を確保するにはどうすればよいでしょうか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    声明:
    この記事はJava学习指南で複製されています。侵害がある場合は、admin@php.cn までご連絡ください。