#############################################I.はじめに##
# 私たちの友人は、RabbitMQ、RocketMQ、Kafka などのメッセージ ミドルウェア MQ について十分に聞いているはずです。ミドルウェアを導入するメリットは、高い同時実行性、ピーキング、ビジネスの分断に対抗する役割を果たす可能性があります。
上に示すように:
(1) オーダー サービスは MQ ミドルウェアにメッセージを配信します (2) ロジスティクス サービスは消費される MQ ミドルウェア メッセージを監視します
シナリオについて話しましょう。MQ サーバーが突然ダウンしたらどうなりますか?注文サービスから送信されたメッセージはすべて消えてしまったのでしょうか?はい、通常、MQ ミドルウェアはシステムのスループットを向上させるためにメッセージをメモリに保存します。他の処理が行われない場合、MQ サーバーがダウンするとすべてのメッセージが失われます。これはビジネスでは許可されていないため、大きな影響を及ぼします。
この場合、MQ サーバーがダウンしても、メッセージは再起動後にディスク ファイルに保存されるため、メッセージは失われません。はい、これにより、メッセージが一定の確率で失われないことが保証されます。
しかし、メッセージが MQ メモリに保存されたばかりで、ディスク ファイルに更新される前に突然クラッシュするというシナリオも考えられます。 (なんと、これは短期間で起こります。確率が低すぎます。) このシナリオは、継続的な大規模メッセージ配信のプロセスでは非常に一般的です。 ######私たちは何をすべきか?ディスクに確実に保存するにはどうすればよいでしょうか?
上記の疑似コードには、次の 2 つの方法があります。メッセージを処理します。これは、ack コールバックと nack コールバックです。(2) メッセージの受信が失敗した場合、MQ はプロデューサーに nack メッセージを返します。
これにより、メッセージが 100% 失われないことが保証されますか?
確認メカニズムを見てみましょう。プロデューサがメッセージを送信するたびに、MQ をディスクに永続化し、ack または nack コールバックを開始する必要があると想像してください。この場合、メッセージを毎回ディスクに保存する必要があるため、MQ のスループットは非常に低くなります。ディスクへの書き込みが非常に遅いです。これは同時実行性が高いシナリオでは受け入れられず、スループットが低すぎます。
MQ 永続ディスクの実際の実装は、非同期呼び出しによって処理され、特定のメカニズムがあり、たとえば、数千のメッセージがある場合、一度にディスクにフラッシュされます。メッセージが届くたびにディスクをフラッシュするのではなく。
つまり、comfirm メカニズムは実際には、システムの高スループットを確保するための非同期リスニング メカニズムです。これは、メッセージが失われないことが 100% 保証されていないことを意味します。確認メカニズムが追加されると、メッセージは失われません。メモリがディスクにフラッシュされる前に MQ がクラッシュし、それでも処理できませんでした。
ここまで言いましたが、まだ保証はできません。どうすればよいでしょうか? ? ?
実は、本質的な理由は、永続化されているかどうかを判断できないことです。では、メッセージを自分で永続化できるでしょうか?答えは「はい」です。私たちの計画はさらに進化します。
上の図のプロセス:
(1) 注文サービスプロデューサーがメッセージを配信する前に、メッセージを Redis または DB に永続化する必要があります。パフォーマンスの高い Redis をお勧めします。メッセージのステータスは送信中です。
(2) 確認メカニズム監視メッセージは正常に送信されましたか? ACK が成功した場合は、Redis でこのメッセージを削除します。
(3) nack が失敗した場合、メッセージを再送信するかどうかは、業務に応じて選択できます。ビジネス上の決定に応じて、このメッセージを削除することもできます。
(4) 一定期間後にメッセージをプルするスケジュールされたタスクがここに追加されます。メッセージ ステータスはまだ送信中です。このステータスは、注文サービスが確認応答メッセージを受信していないことを示します。
(5) スケジュールされたタスクは、補償メッセージを配信します。このとき、MQ コールバック ACK が正常に受信されると、Redis 内でメッセージが削除されます。
このようなメカニズムは実際には補償メカニズムです。MQ が実際にそれを受信するかどうかは関係ありません。Redis 内のメッセージのステータスが [送信中] である限り、メッセージが送信されていることを意味します。正しく受信できませんでした。次に、スケジュールされたタスクを開始して、補償の配信を監視および開始します。
もちろん、スケジュールされたタスクに補正番号を追加することもできますが、3 回を超えても ack メッセージが受信されない場合は、メッセージのステータスを直接 [失敗] に設定し、手動でチェックしてください。なぜですか?
この場合、ソリューションは比較的完璧で、メッセージの 100% が失われないことが保証されています (もちろん、ディスク障害は含まれていないため、マスター/スレーブ ソリューションを使用できます)。
ただし、このソリューションでは、同じメッセージを複数回送信することができます。MQ はすでにメッセージを受信している可能性が非常に高いですが、ack メッセージのコールバック中にネットワーク障害が発生し、プロデューサーはそれを受け取りませんでした。
次に、消費時に冪等性を確保することを消費者に要求する必要があります。
まず、べき等性とは何かを理解しましょう。分散アプリケーションでは、冪等性、つまり、同じ条件でビジネスを実行すれば、何度実行しても結果は同じであることが非常に重要です。
なぜ冪等のようなシナリオがあるのでしょうか?大規模なシステムでは、すべてが分散して展開されるため、たとえば、受注業務と在庫業務が独立して別のサービスとして展開される場合があります。ユーザーが注文すると、注文サービスと在庫サービスが呼び出されます。
分散配置により、インベントリ サービスを呼び出すときに、ネットワークやその他の理由で注文サービスの呼び出しが失敗する可能性が非常に高くなりますが、実際にはインベントリ サービスは処理されており、次の場合にのみ表示されます。処理結果は注文サービスに返されます。例外。この時点で、システムは通常、補償計画を作成します。つまり、注文サービスが在庫サービスを呼び出し、在庫が 1 つ減ります。
#問題があります。実際、最後の呼び出しは 1 減りましたが、注文サービスは処理結果を受け取っていません。ここで再び呼び出され、1 減らす必要があります。これはビジネスに合致しておらず、追加の控除です。
冪等性の概念は、同じ条件でインベントリ サービスを何度呼び出しても、処理結果は同じになるということです。この方法によってのみ、補償計画の実現可能性が保証されます。
フィンガープリント コードは、通常の操作ごとにコードを区別するためのもので、操作ごとに生成され、タイムスタンプのビジネス番号が使用できます。
上記の SQL ステートメント:
戻り値が 0 の場合、操作が実行されていないことを意味します。ビジネス オペレーションの後で実行できます。 t_check (一意の ID フィンガープリント コード) に挿入します。
Return 0 より大きい場合、オペレーションが実行されたことを意味します。
利点: シンプルな実装
欠点: 同時実行性が高い場合のデータベースのボトルネック
解決策: データベースとテーブルを分割するアルゴリズム ルーティングの ID
Redis のアトミック操作を使用して、操作の完了をマークします。このパフォーマンスの方が優れています。しかし、いくつかの問題もあるでしょう。
最初: ビジネス結果をデータベースに保存する必要がありますか?その場合、解決すべき重要な問題は、データベースと Redis 操作でアトミック性を実現する方法です?
これはインベントリが 1 減少することを意味しますが、redis 操作がマークを完了するときに失敗した場合はどうすればよいでしょうか?つまり、データベースの削除と redis が同時に成功するか失敗するかを確認する必要があります。
2 番目: データベースが削除されない場合、両方ともキャッシュに保存されます。同期戦略?
これは、インベントリが 1 減り、インベントリは削除されないことを意味します。Redis 操作を直接実行してマーキングを完了し、別の同期サービスを使用してインベントリを削除します。これは、システムと同期戦略の複雑さが増します。セットアップ方法
以上が[インタビュー] メッセージを 100% 確実に配信するにはどうすればよいですか?メッセージの冪等性を確保するにはどうすればよいでしょうか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。