メッセージキューをプッシュまたはプルします。RocketMQとKafkaはどのように実行しますか?

今日はメッセージキューのプッシュプルモードについて説明します。これはインタビューのホットスポットでもあります。たとえば、履歴書でRocketMQを書いた場合、基本的にRocketMQがプッシュモードとプルモードのどちらを使用するかを尋ねます。プルモードですか?PushConsumerはありませんか?

今日はプッシュプルモデルについて説明し、次にRocketMQとKafkaがどのように実行するかを見ていきます。


プッシュプルモード

まず、メッセージキューのどのステップがプッシュプルモードであるかを明確にします。一般的に、プッシュプルモードについて説明する場合、ComsumerとBrokerの間の相互作用を指します。

デフォルトでは、ProducerとBrokerの間がpushメソッドです。つまり、Producerは、Brokerがメッセージをアクティブにプルする代わりに、Brokerにメッセージをプッシュします。

ブローカーがメッセージをプルする必要がある場合、プロデューサーはメッセージをログの形式でローカルに保存して、ブローカーがメッセージをプルするのを待つ必要があると想像してください。プロデューサーが多数ある場合、メッセージの信頼性はブローカー自体だけでなく、ブローカー自体にも依存します。何百ものプロデューサーに依存します。

ブローカーは、メッセージの信頼できるストレージを確保するために、複数のコピーなどのメカニズムに依存することもできます。数百のプロデューサーの信頼性は少し難しいため、デフォルトのプロデューサーはメッセージをブローカーにプッシュします。

したがって、分散する方が良い場合もありますが、集中管理の方が良い場合もあります。


プッシュモード

プッシュモードとは、ブローカーからコンシューマーにプッシュされるメッセージを指します。つまり、コンシューマーはメッセージを受動的に受信し、ブローカーがメッセージの送信を主導します。

プッシュモードの利点について考えてみましょう。

リアルタイムメッセージは高く、ブローカーはメッセージを受信した直後にそれをコンシューマーにプッシュできます。

消費者にとって使いやすく、シンプルで、待つだけで、どんなニュースもプッシュされます。

プッシュモードの欠点は何ですか?

プッシュレートを消費率に適合させることは困難です。プッシュモデルの目標は、メッセージを最高速でプッシュすることです。ブローカーにメッセージを送信するプロデューサーのレートが、コンシューマーがメッセージを消費するレートよりも大きい場合、コンシューマーは " 「壊れた」、まったく消費がないため。DDos攻撃のようにプッシュレートが速すぎると、消費者は愚かになります。

そして、異なるコンシューマーの消費率は同じではありません。ブローカーとして、各コンシューマーのプッシュレートのバランスをとることは困難です。アダプティブプッシュレートを実現したい場合、コンシューマーがプッシュするタイミングをブローカーに伝える必要があります。私はできません。ゆっくりとプッシュすると、ブローカーは各コンシューマーのステータスを維持してプッシュレートを変更する必要があります。

これは実際にはブローカー自体の複雑さを増します。

このため、プッシュモードは、コンシューマの状態に応じてプッシュレートを制御することが難しく、メッセージ量が少なく、消費電力が大きく、リアルタイム性が要求される状況に適しています。


プルモード

プルモードとは、コンシューマがメッセージをプルするようブローカーにアクティブに要求すること、つまり、ブローカーがメッセージをコンシューマーに受動的に送信することを指します。

プルモードの利点について考えてみましょう。

プルモードのイニシアチブは、自分の条件に基づいてプルリクエストを開始できるコンシューマにあります。現在の消費者は彼がそれを買う余裕がないと感じていると仮定すると、彼は特定の戦略に従ってプルを停止するか、または定期的にプルすることができます。

ブローカーはプルモードで比較的簡単です。ブローカーはプロデューサーから送信されたメッセージのみを保存します。消費に関しては、コンシューマーによって自然に開始されます。要求はブローカーに与えられます。メッセージはメッセージを取得する場所から取得されます。感情のない道具人であり、消費者が手に取らなくても問題ないということを伝えましょう。

プルモードは、メッセージをバッチで送信するのに適しています。プッシュモードに基づいて、1つのメッセージをプッシュするか、一部のメッセージをキャッシュしてからプッシュすることができますが、プッシュするときに、コンシューマが一度に多くのメッセージを処理できるかどうかは不明です。プルモードの方が合理的です。コンシューマから要求された情報を参照して、キャッシュしてバッチで送信するメッセージの数を決定できます。

プルモードの欠点は何ですか?

結局のところ、メッセージの遅延はコンシューマーがメッセージをプルすることですが、コンシューマーはメッセージが到着したことをどのようにして知るのでしょうか。そのため、継続的にプルすることはできますが、リクエストを頻繁に行うことはできません。頻度が高すぎると、ブローカーを攻撃するコンシューマーになります。したがって、リクエストの頻度を減らす必要があります。たとえば、2秒に1回リクエストすると、メッセージを見るときに2秒遅れることがあります。

メッセージビジーリクエスト。ビジーリクエストとは、たとえば、メッセージが数時間後に受信され、コンシューマのリクエストが数時間以内に無効になり、無駄な作業をしていることを意味します。


押すか引くか

プッシュモードとプルモードにはそれぞれ長所と短所があることがわかります。

RocketMQとKafkaの両方がプルモデルを選択しましたが、業界にはActiveMQなどのプッシュモデルベースのメッセージキューもあります。

現在のメッセージキューには永続メッセージが必要なため、つまり、ストレージ機能自体があり、メッセージを受信して​​保存し、コンシューマーがそれらを消費できるようにすることがミッションなので、個人的にはプルモデルの方が適切だと思います。できる。

消費者は多種多様ですが、ブローカーとして、消費者に依存する傾向はないはずです。ニュースは保存してあります。

一般に、消費者のビジネス消費が遅いため、ブローカーはボトルネックにはなりませんが、ブローカーは結局のところ中心であり、可能な限り軽量です。

RocketMQとKafkaはどちらもプルモードを選択しましたが、プルモードの欠点を恐れていませんか?怖いので、彼らは波を操作し、プルモードの欠点を軽減します。


ロングポーリング

RocketMQとKafkaはどちらも「ロングポーリング」を使用してプルモデルを実装しています。これらがどのように動作するかを見てみましょう。

簡単にするために、以下では、ニュースがなく、とにかく条件が満たされていないため、このプルの数と合計サイズを満たさないニュースを一律に説明します。


RocketMQのロングポーリング

RocketMQのPushConsumerは、実際にはプルモードを身に付ける方法ですが、プッシュモードのように見えます。

RocketMQが密かにブローカーに行って舞台裏でデータを要求するのを助けたからです。

バックグラウンドにはRebalanceServiceスレッドがあります。このスレッドは、トピックキューの数と現在のコンシューマグループ内のコンシューマの数に基づいて負荷分散を実行します。各キューによって生成されたpullRequestは、ブロッキングキューpullRequestQueueに入れられます。次に、ブロッキングキューpullRequestQueueからpullRequestを継続的に取得し、ネットワークを介してブローカーに要求する別のPullMessageServiceスレッドがあり、準リアルタイムでメッセージをプルできます。

私はコードのこの部分を切り取らないでください、それはちょうどそのようなものです、私はそれを後で絵で示します。

次に、ブローカーのPullMessageProcessorのprocessRequestメソッドを使用して、メッセージのプルリクエストを処理します。メッセージがある場合は、直接返されます。メッセージがない場合はどうなりますか?コードを見てみましょう。

suspendPullRequestメソッドの機能を見てみましょう。

PullRequestHoldServiceスレッドは、5秒ごとにpullRequestTableからPullRequestリクエストをフェッチし、プルされるメッセージリクエストのオフセットが現在の消費キューの最大オフセットよりも小さいかどうかを確認します。条件がtrueの場合、新しいメッセージが存在し、notifyMessageArrivingが呼び出されます。最後に、PullMessageProcessorのexecuteRequestWhenWakeup()メソッドが呼び出されて、このメッセージの要求の処理を再試行する(つまり、再度実行する)デフォルトの長いポーリング時間は30秒です。

簡単に言えば、5秒ごとにメッセージをチェックする時間です。チェックされている場合は、processRequestを呼び出してメッセージを再度処理します。リアルタイムじゃないですか?5秒?

心配しないでください。ReputMessageServiceスレッドもあります。このスレッドを使用して、commitLogからのデータを継続的に解析し、リクエストを配布して、ConsumeQueueとIndexFileの2種類のデータを作成します。また、5秒ごとにウェイクアップリクエストが発生します。遅い遅延

コードをインターセプトしません。つまり、メッセージが書き込まれ、pullRequestHoldService#notifyMessageArrivingが呼び出されます。

最後に、プロセス全体を説明するために絵を描きます。


カフカでの長期投票

Kafkaと同様に、プルリクエストにはパラメータがあり、「ロングポーリング」でコンシューマリクエストをブロック待機させることができます。

簡単に言うと、コンシューマーはブローカーに移動してメッセージをプルし、タイムアウト期間を定義します。これは、コンシューマーがメッセージを要求し、メッセージがある場合はすぐにメッセージを返すことを意味します。そうでない場合、コンシューマーはタイムアウトになるまで待機し、プルメッセージの要求を再度開始します。 。

また、ブローカーも協力する必要があり、コンシューマーが要求した場合は、すぐにメッセージを返す必要があります。メッセージがない場合は、遅延オペレーションが確立され、戻る前に条件が満たされます。

ソースコードを簡単に見てみましょう、要点を強調するために、コードをいくつか切り取ります。

最初に消費者コードを見てみましょう。

上記の投票インターフェースは、誰もがよく知っている必要があります。実際、データの到着またはタイムアウトを実際に待っていることがコメントから直接わかります。簡単に見てみましょう。

最後のclient.pollが呼び出すものを見てみましょう。

最後の呼び出しはKafkaによってラップされたセレクターであり、最後にJava nioのselect(timeout)が呼び出されます。

コンシューマーコードが明確になったので、Brokerがどのように行うかを見てみましょう。

ブローカーがすべてのリクエストを処理するためのエントリは、実際には前回の記事のKafkaApis.scalaファイルのハンドルメソッドの下に導入されました。今回は主人公がhandleFetchRequestです。

この方法が入ってくる、私は最も重要な部分を傍受します。

次の図は、fetchMessagesメソッドの内部実装です。ソースコードによって与えられたコメントはすでに非常に明確です。拡大して見ることができます。

この煉獄の名前はとても興味深いです。簡単に言うと、前回の記事で言及したタイムホイールを使用してタイミングタスクを実行することです。たとえば、delayedFetchPurgatory遅延プル操作の処理に特に使用されます。

まず、この遅延オペレーションに実装する必要があるメソッドについて簡単に考えてみましょう。まず、構築された遅延オペレーションには、メッセージが到着したかどうかをチェックするチェックメカニズムが必要です。次に、メッセージが到着した後に実行するメソッドがあり、それを実行する必要があります。もちろん、終了後に何をすべきかは、タイムアウト後に行う方法がなければなりません。

これらのメソッドは、実際にはコード内のDelayedFetchに対応しています。このクラスはDelayedOperationを継承し、以下を持っています:

  • 条件が満たされているかどうかを確認するisCompletedメソッド

  • 条件が満たされた後に実行されるtryCompleteメソッド

  • onCompleteの実行後に呼び出されるメソッド

  • onExpirationの期限が切れた後に実行する必要があるメソッド

期限切れかどうかの判断はタイムホイールによって行われますが、それが終わったときにニュースを見るのが待ちきれませんよね?

ここでのKafkaとRocketMQのメカニズムは同じです。メッセージが書き込まれるときに、これらの遅延された要求メッセージを思い出させます。特定のコードは投稿しません。ReplicaManager#appendRecordsメソッドには、さらに2つのメソッドがあります。

コードは掲載されていませんが、絵を描く必要があります。


概要

RocketMQとKafkaの両方が「ロングポーリング」メカニズムを採用していることがわかります。具体的な方法は、コンシューマーを介してメッセージを待つことです。メッセージがある場合、ブローカーはメッセージを直接返します。メッセージがない場合は、遅延処理戦略を採用します。メッセージの適時性を確保するために、新しいメッセージが対応するキューまたはパーティションに到着すると、メッセージが来て、時間内にメッセージを返すように通知します。

つまり、コンシューマーとブローカーは、プルメッセージリクエストが条件を満たしていない場合に連携して保持し、複数の頻繁なプルアクションを回避し、メッセージが到着したらすぐに戻るように通知します。

 

やっと

一般的に言って、プッシュプルモードには長所と短所があり、個人的にはプルダウンモードの方がメッセージキューに向いていると思います。

方法はありませんが、テクニックは達成できます。方法がない場合は、テクニックで終わります

みんながJava Wayパブリックアカウントをフォローすることを歓迎します

良い記事、私は読んでいます❤️

おすすめ

転載: blog.csdn.net/hollis_chuang/article/details/108480421