インタビューの観点から問題を見てください: メッセージ キューの詳細な説明 (1 万語の長いテキスト、絶対に読む価値があります)


序文

メッセージキューは、面接や開発過程でよく使われるものですが、この記事では、面接官からの質問をシミュレートし、メッセージキューの内容をできるだけ詳しく紹介し、メッセージキューの内容を理解しやすくすることを目的としています。写真を挿入することによって。

特記事項:この記事の内容の一部は、インタビュー本やその他の資料からのものであり、参考用です。


1. メッセージキューとは?

メッセージ キューの内容を紹介する前に、メッセージ キューの定義を明確にする必要があります。

メッセージ キュー (Message Queue) は、アプリケーション間の通信方法であり、メッセージを送信するとすぐにメッセージを返すことができ、メッセージ システムによりメッセージの確実な配信が保証されます。メッセージ パブリッシャーは、誰がメッセージを取得するかに関係なく、メッセージを MQ にパブリッシュするだけであり、メッセージ ユーザーは、誰がパブリッシュするかに関係なく、MQ からメッセージを取得するだけです。このように、発行者も利用者も相手の存在を知る必要はありません。

メッセージ キュー ミドルウェアは、分散システムにおける重要なコンポーネントであり、主にアプリケーション デカップリング、非同期メッセージ、トラフィック シェービングなどの問題を解決し、高性能、高可用性、スケーラビリティ、結果整合性アーキテクチャを実現します。現在使用されているメッセージ キューは、ActiveMQ、RabbitMQ、ZeroMQ、Kafka、MetaMQ、RocketMQ です。
ここに画像の説明を挿入

2. メッセージ キューを使用する理由

メッセージ キューには、分離、非同期、ピーク シェービングという 3 つの一般的な利点があります。

1.デカップリング

デカップリングは開発プロセスにおける基本的な要件であり、メッセージ キューはシステム コンポーネントのデカップリングを十分に実現できます。

最初にシナリオを見てみましょう。
システム A が 3 つの BCD システムにデータを送信し、インターフェイス呼び出しを介してそれらを送信します。E システムでもこのデータが必要な場合はどうすればよいでしょうか? では、C システムが不要になったらどうなるでしょうか。
ここに画像の説明を挿入
システム A は、他のさまざまな乱雑なシステムと強く結合しています。システム A は、重要なデータの一部を生成し
、多くのシステムは、システム A がこのデータを送信する必要があります。システム A は常に BCDE の 4 つのシステムを考慮する必要があります。4 つのシステムに障害が発生した場合はどうすればよいですか? 再送信しますか、メッセージを保存しますか?

このシナリオから、変更が発生すると、この 1 対 1 の接続方法は非常に面倒になることがわかります. システム間の結合関係は非常に強く、複数のシステムのコードを変更する必要があります.

明らかに、これは理想的な方法ではありません。

メッセージ キューは、この問題をうまく解決できます。

特定の使用法: MQ を使用して、システム A はデータの一部を生成し、それを MQ に送信します。このシステムは、MQ でそれ自体を消費するデータを必要とします。新しいシステムがデータを必要とする場合は、MQ から直接消費できます。システムがこのデータを必要としない場合は、MQ メッセージの消費をキャンセルするだけです。このように、システム A は誰にデータを送信するかを考える必要がなく、このコードを維持する必要がなく、呼び出しが成功したかタイムアウトに失敗したかを考慮する必要がありません。
ここに画像の説明を挿入
MQ と Pub/Sub のパブリッシングおよびサブスクライブ メッセージのモデルを通じて、システム A は他のシステムから完全に切り離されます。

2. 非同期

別のシナリオを見てみましょう. システム A が要求を受け取ると、ライブラリをローカルに書き込む必要があり、BCD 3 つのシステムにもライブラリを書き込む必要があります. ライブラリをローカルに書き込むのに 3ms かかり、300ms、450ms、200ms かかります3 つの BCD システムがそれぞれライブラリを書き込むため。最終リクエストの合計遅延は 3+ 300 + 450 + 200 = 953ms で、これは 1 秒に近く、ユーザーは何かが死ぬほど遅いと感じます。ユーザーがブラウザーを介して要求を開始し、1 秒を待つことは、ほとんど受け入れられません。
ここに画像の説明を挿入

メッセージ キューを使用すると、この問題も解決できます。

具体的な方法は次のとおりです: MQ を使用すると、システム A は連続して 3 つのメッセージを MQ キューに送信します. 5ms かかる場合、システム A が要求を受信して​​ユーザーに応答を返すまでの合計時間は 3 + 5 = 8ms です.実際、ユーザーはボタンをクリックするような感覚で、8 ミリ秒後にすぐに戻ります。
953 ミリ秒から 8 ミリ秒に、パフォーマンスが 100 倍以上向上しました.これは、MQ メカニズムによってもたらされた利点です.これが、通常、ファイルをアップロードしたり、コンテンツを公開したりする理由です.

ここに画像の説明を挿入
ローカル ディスプレイには、アップロードが成功したか、または公開は成功しましたが、他のユーザーはまだ短期間です。表示できません。更新には時間がかかります。

これは、実際にはデータの同期に時間がかかるためです. ローカルで見られるアップロードの成功は、実際にはデータを MQ に正常にアップロードしたという事実ですが、MQ がデータベースに書き込まれるまでにはまだ一定の時間がかかります (現在、この遅延は非常に短い)、そのため、他のユーザーは当面それを見ることができず、MQ のデータがデータベースに格納されるのを待ってから、他のユーザーがコンテンツを見ることができます**

3. ピーククリッピング

別のシナリオを見てみましょう。毎日 0:00 から 12:00 まで、システム A は落ち着いていて、1 秒あたりの同時要求数はわずか 50 です。その結果、12:00 から 13:00 まで毎回、1 秒あたりの同時リクエスト数が 5k+ に急増しました。しかし、システムは直接 MySQL に基づいており、大量のリクエストが MySQL に流れ込み、MySQL では 1 秒あたり約 5,000 の SQL が実行されます。
ここに画像の説明を挿入

一般的な MySQL では、1 秒あたり 2k のリクエストを処理するのにほぼ十分ですが、リクエストが 1 秒あたり 5k に達すると、MySQL が直接強制終了され、システムがクラッシュし、ユーザーがシステムを使用できなくなります (申し訳ありません)。 wb貰ったと思ったら、何か大きなイベントがあるとホットサーチが崩壊してしまうwwww)

しかし、ピーク期間が終わると、午後は低いピーク期間になり、Web サイトで同時に操作しているユーザーは 10,000 人だけであり、1 秒あたりのリクエスト数はわずか 50 リクエストである可能性があります。システム全体への影響はありません。

メッセージ キューを使用すると、この問題もある程度解決できます。

なぜある程度だと言えるのですか?

メッセージキューはシステム処理のパフォーマンスを直接改善するわけではありませんが、単位時間あたりにシステムに入るデータリクエストを制限して、システムが崩壊しないようにし、要求のバックログが MQ に存在するか、直接例外をスローするためです。

具体的な方法: MQ を使用すると、1 秒あたり 5k の要求が MQ に書き込まれ、MySQL は 1 秒あたり最大 2k の要求を処理できるため、システム A は 1 秒あたり最大 2k の要求を処理できます。

システム A は MQ からゆっくりとリクエストをプルし、1 秒あたり 2k のリクエストをプルします。1 秒あたりに処理できる最大リクエスト数を超えなければ問題ありません。このようにして、ピーク時でもシステム A がハングアップすることはありません。 .

しかし、MQ には毎秒 5,000 のリクエストが入り、2,000 のリクエストしか出ないため、正午 (1 時間) のピーク時に数十万、場合によっては数百万のリクエストが MQ にバックログされる可能性があります。
ここに画像の説明を挿入
この短いピーク期間のバックログは問題ありません。ピーク期間の後、1 秒あたり 50 リクエストが MQ に入りますが、システム A は 1 秒あたり 2k リクエストの速度で処理を続けるためです。したがって、ピーク期間が過ぎるとすぐに、システム A はメッセージのバックログを迅速に解決します (また、一部の要求はタイムリーであり、メロンを食べる大多数の人々など、しばらくするとデータを要求する必要がない場合があります)。

3. メッセージ キューの短所は何ですか?

これを見て、メッセージ キューには多くの利点があり、非常に強力であり、パフォーマンスを大幅に向上させ、大量の要求が発生してもシステムがクラッシュしないようにすることができると思いますか?

欠点は何ですか?

1. システムの可用性の低下

システムが導入する外部依存が多いほど、ハングアップしやすくなります元々、BCD の 3 系統のインターフェースを呼び出すシステム A であり、ABCD の 4 系統はまだ問題ありません。MQ を追加するだけで、MQ がハングアップした場合はどうなりますか? MQ がハングアップすると、システム全体がクラッシュします

2. システムの複雑化

MQ に参加した後、** メッセージが繰り返し消費されないようにする方法は? メッセージロスの状況にどう対処するか? メッセージ配信の順序を保証するには? **他の一連の問題につながります。

3. 一貫性の問題

システムAはMQに参加してからリクエストが成功したと思っているので、そのまま処理後に成功を返すのですが、問題は、BCDとBDの3つのシステムがデータベースの書き込みに成功すると、結果としてシステムCはデータベースの書き込みに失敗するということです。 . データの不整合につながります。データの不整合は非常に大きな問題であり、慎重に検討する必要があります。

メッセージキューは実際には非常に複雑なアーキテクチャです. 導入すると多くの利点が得られますが, さまざまな追加の技術的解決策とアーキテクチャを実行して, それがもたらす欠点を回避する必要があります. うまく実行すると, システムが複雑. 速度は桁違いに増加し、おそらく 10 倍複雑になります。ただし、特に大規模なシステムでは、重要な瞬間に使用する必要があります。

4. メッセージ キューの高可用性を確保するにはどうすればよいですか?

1.RabbitMQ の高可用性

高可用性のためにマスター/スレーブ (非分散型) に基づいているため、RabbitMQ がより代表的です。RabbitMQ を例として使用して、最初の MQ の高可用性を実現する方法を説明します。

RabbitMQ には、スタンドアロン モード、共通クラスター モード、ミラー クラスター モードの 3 つのモードがあります。

1) スタンドアロンモード

スタンドアロン モードはデモ レベルで、通常はローカルで開始され、本番環境でスタンドアロン モードを使用する人はいません。

2) 通常のクラスタ モード: 高可用性なし

通常のクラスター モードとは、複数のマシンで複数の RabbitMQ インスタンスを、マシンごとに 1 つずつ開始することを意味します。作成したキューは 1 つの RabbitMQ インスタンスにのみ配置されますが、各インスタンスはキューのメタデータを同期します (メタデータはキューの構成情報と見なすことができ、メタデータを通じて、キューが配置されているインスタンスを見つけることができます)。消費するとき、実際に別のインスタンスに接続すると、そのインスタンスはキューが配置されているインスタンスからデータをプルします。
ここに画像の説明を挿入
この方法は本当に面倒であまり良くない. いわゆる分散を実現していない. ただの普通のクラスタだ. これは、コンシューマが毎回インスタンスにランダムに接続してからデータをプルするか、キューが配置されているインスタンスに永続的に接続してデータを消費することにつながるためです. 前者にはデータプルのオーバーヘッドがあり、後者には単一インスタンスが発生します.パフォーマンスのボトルネック。

また、キューを配置したインスタンスがダウンしている場合、他のインスタンスはそのインスタンスからプルすることができません. メッセージの永続性を有効にして、RabbitMQ がメッセージを地上に保存できるようにすると、メッセージが失われない可能性があります. これを待つ必要があります.インスタンス リカバリ後、このキューから引き続きデータを取得できます。

つまり、この問題はさらに厄介です. いわゆる高可用性はありません. この解決策は主にスループットを向上させることです. つまり, クラスター内の複数のノードが特定のキューの読み取りおよび書き込み操作を実行できるようにすることです.

3) ミラー クラスタ モード: 高可用性

このモードは、RabbitMQ のいわゆる高可用性モードです。通常のクラスター モードとは異なり、ミラー クラスター モードでは、作成したキューは、キュー内のメタデータまたはメッセージに関係なく、複数のインスタンスに存在します。

つまり、各 RabbitMQ ノードには、キューのすべてのデータを含むキューの完全なイメージがあります。その後、キューにメッセージを書き込むたびに、メッセージは複数のインスタンスのキューに自動的に同期されます。
ここに画像の説明を挿入
この場合の利点は、いずれかのマシンがダウンしても問題がなく、他のマシン (ノード) にもこのキューの完全なデータが含まれているため、他のコンシューマーが他のノードに移動してデータを消費できることです。
欠点は、第一に、パフォーマンスのオーバーヘッドが高すぎることです.メッセージはすべてのマシンに同期する必要があるため、大きなプレッシャーとネットワーク帯域幅の消費が発生します!

第二に、このプレイ方法は分散されていないため、スケーラビリティがまったくありません.キューの負荷が高いときにマシンを追加すると、新しく追加されたマシンにもこのキューのすべてのデータが含まれ、直線的に拡張する方法がありません. . あなたのキュー。このキュー内のデータ量が多すぎて、このマシンの容量に対応できない場合、この時点でどうすればよいと思いますか?

2. Kafka の高可用性

Kafka の最も基本的なアーキテクチャの理解の 1 つ: それは複数のブローカーで構成され、各ブローカーはノードです; 複数のパーティションに分割できるトピックを作成し、各パーティションは異なるブローカーに存在でき、各パーティションはいくつかのデータ。
ここに画像の説明を挿入

これは自然な分散メッセージ キューです。つまり、トピックのデータが複数のマシンに分散され、各マシンがデータの一部を置きます。

実際、RabbitMQ などは分散型メッセージ キューではなく、従来のメッセージ キューであり、クラスタリングと HA (高可用性、高可用性) メカニズムを提供するだけです。ミラーリング クラスタの下では、各ノードもキューの完全なデータを格納します。

Kafka 0.8 より前は、HA メカニズムはありませんでした。つまり、ブローカーがダウンした場合、そのブローカーのパーティションは廃止され、書き込みや読み取りができなくなり、言及する高可用性もありませんでした。
たとえば、トピックが作成され、そのパーティションの数が 3 に指定され、それぞれが 3 台のマシン上にあるとします。ただし、2 台目のマシンがダウンすると、このトピックのデータの 1/3 が失われるため、これは高可用性とは言えません。

Kafka 0.8 以降では、レプリカ (レプリカ) のコピー メカニズムである HA メカニズムが提供されます。各パーティションのデータは他のマシンと同期され、独自の複数のレプリカ コピーが形成されます。すべてのレプリカがリーダーを選出し、プロダクションとコンシュームがこのリーダーを処理し、他のレプリカがフォロワーになります。書き込みの場合、リーダーはすべてのフォロワーにデータを同期する責任を負い、読み取りの場合は、リーダーのデータを直接読み取るだけです。

リーダーしか読み書きできないのはなぜですか?

それは非常に単純です. 各フォロワーを自由に読み書きできる場合, データの一貫性の問題に対処する必要があります. システムの複雑さが高すぎて, 簡単にうまくいかない. Kafka は、フォールト トレランスを向上させるために、パーティションのすべてのレプリカを異なるマシンに均等に分散します。
ここに画像の説明を挿入
このようにして、いわゆる高可用性が実現します。これは、特定のブローカーがダウンしても問題がなく、そのブローカーのパーティションのコピーが他のマシンにあるためです。壊れたブローカーにパーティション リーダーがある場合、この時点で新しいリーダーがフォロワーから再選出され、誰もが新しいリーダーの読み書きを続行できます。これは高可用性と呼ばれます。

データを書き込むときは、プロデューサーがリーダーに書き込み、リーダーがデータをローカル ディスクに書き込み、他のフォロワーがリーダーから積極的にデータをプルします。すべてのフォロワーがデータを同期すると、リーダーに ack が送信され、リーダーがすべてのフォロワーの ack を受信すると、書き込み成功メッセージがプロデューサーに返されます。(もちろん、これはモードの 1 つにすぎず、この動作は適切に調整できます)

消費する場合、メッセージはリーダーからのみ読み取られますが、メッセージがすべてのフォロワーによって同期的に正常に ack に返された場合にのみ、メッセージはコンシューマーによって読み取られます。

5. メッセージが繰り返し消費されないようにする方法 (メッセージ消費の冪等性)?

1.メッセージの繰り返し消費の問題は何ですか

最初にシナリオを使用して、メッセージの繰り返し消費の問題を紹介します。

Kafka には実際にはオフセットの概念があります。つまり、書き込まれた各メッセージには、メッセージのシリアル番号を表すオフセットがあり、コンシューマーがデータを消費した後、時々 (定期的に) メッセージを消費します。 「もう消費してしまったので、次回再起動するか何かしたら、前回消費したオフセットから継続して消費させてください」と言って、オフセットを提出します。

しかし、何事にもアクシデントはつきもので、例えば以前の本番でよく遭遇したのは、システムを再起動して様子を見ようとする場合があり、急いでいる場合はプロセスを直接 kill してから再起動するというものです。これにより、コンシューマはいくつかのメッセージを処理しますが、オフセットを送信する時間がなく、恥ずかしいことです。再起動後、少数のメッセージが再び消費されます。

そんなシーンがあります。Data 1/2/3 が順番に Kafka に入り、Kafka はこれら 3 つのデータのそれぞれにオフセットを割り当て、このデータのシリアル番号を表します。順序。コンシューマーが kafka から消費する場合、消費者もこの順序で消費します。コンシューマがオフセット=153 のデータを消費し、オフセットを ZooKeeper に送信する準備をするだけの場合、コンシューマ プロセスは再起動されます。この時点で消費されたデータの 1/2 のオフセットが送信されていないため、Kafka はオフセット = 153 でデータを消費したことを知りません。再起動後、コンシューマーは Kafka を見つけて、前回消費した場所の背後にあるデータを渡してくれと言います。以前のオフセットが正常に送信されなかったため、データの 1/2 が再度送信されます。この時点でコンシューマーが重複排除を行わないと、消費が繰り返されます。
ここに画像の説明を挿入
消費者がデータの一部をデータベースに書き込むことである場合、データの 1/2 をデータベースに 2 回挿入してもよいと言うことにつながり、データは間違っています。
実際、繰り返し消費はひどいものではありません. ひどいのは、繰り返し消費した後に冪等性を保証する方法を考慮していないことです.

例を挙げましょう。メッセージを消費し、データの一部をデータベースに挿入するシステムがあるとします. メッセージを 2 回繰り返すと、2 つのデータが挿入されます. データは間違っていませんか? ただし、2回目に消費する場合は、すでに消費したかどうかを自分で判断し、消費した場合は破棄して、データの一部が保持されないようにして、データの正確性を確保してください. 1 つのデータが 2 回表示される場合、データベースには 1 つのデータしかないため、システムのべき等性が保証されます。

冪等性、簡単に言えば、1 つのデータまたは 1 つの要求が何度も繰り返される場合、対応するデータが変更されず、間違いを犯さないことを確認する必要があります。

2.メッセージの繰り返し消費の問題を解決する方法

(1)例えば
、データベースにデータを書きたい場合は、まず主キーでチェックし、データがあれば挿入せずに更新する。

(2) 例えば、Redis を書いている場合は問題ありません. とにかく、毎回設定されているため、当然冪等です。

(3) たとえば、上記の 2 つのシナリオに当てはまらない場合は、もう少し複雑になります. 各データを送信するときに、プロデューサーがグローバルに一意の ID (オーダー ID など) を追加できるようにする必要があります。ここで消費する 到着したら、まずこの id に従って Redis にチェックインします。以前に消費したことがありますか? 消費されていない場合は、それを処理してから、ID を Redis に書き込みます。すでに消費している場合は、対処する必要はありません。同じメッセージを繰り返し処理しないようにしてください。

(4) たとえば、データベースの一意のキーに基づいて、重複するデータが繰り返し挿入されないようにします。一意のキー制約があるため、繰り返しデータを挿入してもエラーが報告されるだけで、データベースにダーティ データが発生することはありません。

ここに画像の説明を挿入

6. メッセージの信頼できる送信を確保するにはどうすればよいですか (メッセージ損失の問題)?

MQ を使用する基本原則があります。つまり、データの増減はなく、それ以上のデータはありません。これは、
前述の消費の繰り返しと冪等性の問題です。つまり、このデータを失わないでください。

1.うさぎMQ

MQ を使用して請求メッセージや控除メッセージなどの非常に重要なメッセージを送信する場合は、MQ 転送プロセス中に請求メッセージが失われないようにする必要があります。
ここに画像の説明を挿入

1). 着信プロセス中にメッセージが失われる

プロデューサーがRabbitMQにデータを送信する際、ネットワークの問題などでデータが途中で失われることがあります。

このとき、RabbitMQ が提供するトランザクション機能を使用することを選択できます、つまり、プロデューサーはデータを送信する前に RabbitMQ トランザクション channel.txSelect を開き、メッセージを送信します.メッセージが RabbitMQ によって正常に受信されない場合、プロデューサーは例外エラーを受け取り、トランザクション channel.txRollback をロールバックしてから、メッセージの送信を再試行できます。メッセージが受信された場合、トランザクション channel.txCommit をコミットできます。

// 开启事务
	channel.txSelect
try {
    
    
	// 这里发送消息
} catch (Exception e) {
    
    
	channel.txRollback
	// 这里再次重发这条消息
}
	// 提交事务
	channel.txCommit

しかし問題は、RabbitMQ トランザクション メカニズム (同期、ニーズなど) が実装されると、パフォーマンスを消費しすぎるため、基本的にスループットが低下することです。

したがって、一般に、RabbitMQ に書き込まれたメッセージが失われないようにしたい場合は、確認モードを有効にすることができます。プロデューサーで確認モードを設定すると、書き込む各メッセージに一意の ID が割り当てられます。 write RabbitMQ では、RabbitMQ は ack メッセージを返し、メッセージが OK であることを伝えます。RabbitMQ がメッセージの処理に失敗した場合、nack インターフェースの 1 つをコールバックして、メッセージの受信に失敗したことを通知し、再試行できます。また、このメカニズムを組み合わせて、各メッセージ ID の状態をメモリ内に維持することもできます.一定時間経過してもこのメッセージのコールバックを受信して​​いない場合は、再送信できます.

トランザクションメカニズムと確認メカニズムの最大の違いは、トランザクションメカニズムが同期であることです.トランザクションを送信すると、そこでブロックされますが、確認メカニズムは非同期です.メッセージを送信した後、次のメッセージを送信できます. 、次にRabbitMQが受け取るメッセージメッセージが受信された後、非同期的にインターフェイスの1つをコールバックして、メッセージが受信されたことを通知します。

したがって、プロデューサは通常、確認メカニズムを使用してデータの損失を回避します。

2).RabbitMQ の失われたデータ

つまり、RabbitMQ 自体がデータを失った. RabbitMQ の永続性を有効にする必要があります.つまり、メッセージが書き込まれた後、メッセージはディスクに永続化されます. RabbitMQ が単独でハングアップした場合でも、以前に保存されたデータを自動的に読み取ります.通常、データは残りません。永続化する前に RabbitMQ がハングアップすることが非常にまれな場合を除き、少量のデータ損失が発生する可能性がありますが、この確率は小さいです。

永続性を設定するには 2 つの手順があります。1
つ目は、キューの作成時に永続性として設定することです。これにより、RabbitMQ はキューのメタデータが永続化されていることを確認できますが、キュー内のデータは永続化されません。

2 つ目は、メッセージを送信するときにメッセージの deliveryMode を 2 に設定して、
メッセージが永続的であるように設定することです.このとき、RabbitMQ はメッセージをディスクに永続化します.

この 2 つの永続性は同時に設定する必要があり、RabbitMQ がハングアップして再起動しても、再起動してディスクからキューを復元し、キュー内のデータを復元します。

RabbitMQ の永続化メカニズムを有効にしても、このメッセージが RabbitMQ に書き込まれる可能性があることに注意してください。少しのデータが失われます。

したがって、永続化はプロデューサー側の確認メカニズムと組み合わせることができます. メッセージがディスクに永続化された後にのみ、プロデューサーに ack が通知されるため、ディスクに永続化される前でも、RabbitMQ はハングアップし、データは紛失した場合、プロデューサーは確認応答を受信できません。自分で再送信することもできます。

3). 消費者がデータを失う

RabbitMQ がデータを失った場合、それは主に、消費したときに消費されたばかりで処理されていないことが主な原因です. 結果として、再起動などのプロセスがハングアップし、恥ずかしい.データが失われます。

このとき、RabbitMQ が提供する ack メカニズムを使用する必要があります. 簡単に言えば、api を介して呼び出すことができる RabbitMQ の自動 ack をオフにする必要があり、その後、独自のコードで処理が完了するたびに、次に、プログラム Bundle を確認します。この場合、処理が終わっていない場合は、ACK が来ませんか?その後、RabbitMQ は処理が完了していないと見なします. この時点で、RabbitMQ はこの消費を他のコンシューマーに割り当てて処理するため、メッセージが失われることはありません.
ここに画像の説明を挿入

2.カフカ

1) 消費者がデータを失う

コンシューマーがデータを失う原因となる可能性がある唯一の状況は、メッセージをコンシュームした後、コンシューマーが自動的にオフセットを送信することです。これにより、Kafka はメッセージを既にコンシュームしたと見なしますが、実際にはメッセージを処理しようとしています。対処する前に電話を切ると、この時点でこのメッセージは失われます。

これはRabbitMQに似ていませんか? Kafkaがオフセットを自動的に送信することは誰もが知っているので、オフセットの自動送信をオフにして、処理後に手動でオフセットを送信する限り、データが失われないことを保証できます. ただし、この時点ではまだ消費が繰り返される可能性があります. たとえば、処理を終了したばかりでオフセットを提出していないのに電話を切った. このとき、間違いなくもう一度消費します. 冪等性を自分で確認してください.

2) カフカはデータを失った

この分野でより一般的なシナリオの 1 つは、Kafka の特定のブローカーがダウンし、パーティションのリーダーを再選することです。考えてみてください。他のフォロワーがたまたま同期されていないデータを持っていて、リーダーがこの時点で電話を切った場合、フォロワーをリーダーに選出した後、一部のデータが失われることはありませんか? これにより、一部のデータが失われました。

そのため、現時点では、通常、少なくとも次の 4 つのパラメーターを設定する必要があります

Kafka サーバーで min.insync.replicas パラメーターを設定します。この値は 1 より大きい必要があります。これには、リーダーが少なくとも 1 人のフォロワーがいることを認識し、自分自身と連絡を取り合う必要があります。リーダーが電話を切った後もフォロワーのままです。

プロデューサー側で acks=all を設定します。これは、データの各部分がすべてのレプリカに書き込まれてから成功したと見なされるようにするためです。

プロデューサー側で retries=MAX を設定します (非常に大きな値、つまり無限の再試行を意味します): これは、書き込みが失敗すると無限に再試行するように要求するためのもので、ここでスタックします。

この構成の後、少なくとも Kafka ブローカー側では、リーダーが配置されているブローカーに障害が発生した場合、リーダーが切り替えられたときにデータが失われないことが保証されます。

3) プロデューサーはデータを失いますか?

上記の考え方に従って acks=all を設定すると、メッセージが失われることはありません. 要件は、リーダーがメッセージを受信し、すべてのフォロワーがメッセージと同期した後、書き込みが成功したと見なされることです. この条件が満たされない場合、プロデューサーは自動的に継続的に再試行し、無限に再試行します。

7. メッセージ キューを作成するように求められた場合、アーキテクチャをどのように設計する必要がありますか?

たとえば、このメッセージ キューイング システムについて、次の観点から考えてみましょう。

まず、この mq はスケーラビリティをサポートする必要があります。つまり、スループットと容量を増やすために、必要に応じて容量をすばやく拡張する必要があります。分散システムを設計するには、kafka の設計概念を参照して、ブローカー -> トピック -> パーティションに、データの一部を格納するマシンを各パーティションに配置します。現在リソースが十分でない場合は、トピックにパーティションを追加してからデータ移行を行い、マシンを追加して、より多くのデータを保存し、スループットを向上させますか?

次に、この mq のデータをディスクに配置するかどうかを検討する必要がありますよね? これは必須であり、ディスクを使用して、プロセスがハングアップした場合にデータが失われないようにすることができます。ディスクを落としたとき、どのように落ちましたか? シーケンシャルな書き込みにより、ランダムなディスクの読み取りと書き込みのアドレッシング オーバーヘッドがなくなり、シーケンシャルなディスクの読み取りと書き込みのパフォーマンスが非常に高くなります。これが Kafka の考え方です。

第二に、mq の可用性を考慮していますか? この点については、前述の可用性のリンクで説明されている Kafka の高可用性保証メカニズムを参照してください。複数のコピー -> リーダーとフォロワー -> ブローカーが電話を切り、外の世界に奉仕するリーダーを再選します。

データ 0 損失をサポートできますか? はい、前述の Kafka データ損失ゼロ ソリューションを参照してください

おすすめ

転載: blog.csdn.net/qq_46119575/article/details/129794304