メッセージキューとは何ですか?簡単に言えば、メッセージ キューはメッセージを保存するためのコンテナーです。クライアントはメッセージ サーバーにメッセージを送信したり、メッセージ サーバーからメッセージを取得したりできます。
画像はPexelsより 今日は、以下の問題について私の考えを述べたいと思います。
なぜメッセージングシステムが必要なのでしょうか? ピークシェービング データベースの処理能力には限界があります。ピーク時には、多くのリクエストがバックグラウンドに落ちてしまいます。システムの処理能力を超えると、システムがクラッシュする可能性があります。 上図に示すように、システムの処理能力は 2k/s、MQ 処理能力は 8k/s、ピーク要求は 5k/s です。 MQ の処理能力はデータベースよりもはるかに優れています。ピーク時には、リクエストはまず MQ に蓄積され、システムは自身の処理能力に基づいて 2k/s の速度でこれらのリクエストを消費することができます。 この方法では、ピーク期間が終了すると、リクエスト レートは 100/秒のみになり、システムは MQ 内のリクエストのバックログを迅速に消費できます。 上記のリクエストは書き込みリクエストを指し、クエリ リクエストは通常キャッシュを通じて解決されることに注意してください。 デカップリング 次のシナリオでは、システム S はシステム A、B、C と密接に結合されています。要件の変更により、システム A は関連コードを変更し、システム S でも A 関連コードを調整する必要がありました。 数日後、C システムを削除する必要があり、S もそれに倣って C 関連のコードを削除します。数日後、D システムを追加する必要があり、S システムに D 関連のコードを追加する必要があります。数日後、プログラマーたちは発狂してしまいました... これにより、システムが緊密に結合され、メンテナンスや拡張が容易ではなくなります。ここで MQ が導入されます。システム A が変更された場合、A は独自のコードを変更できます。システム C が削除された場合は、直接登録解除できます。システム D が追加されると、関連するメッセージをサブスクライブできるようになります。 このように、メッセージ ミドルウェアを導入することで、各システムは MQ と対話できるようになり、システム間の複雑な呼び出し関係を回避できます。 Kafka のアーキテクチャ原則は何ですか? Kafka 関連の概念:
トピックとログ メッセージはトピックごとに整理され、各トピックは複数のパーティション (server.properties/num.partitions に対応) に分割できます。 パーティションは、ディスクへのシーケンシャル書き込みに属するシーケンシャル追加ログです (ディスクへのシーケンシャル書き込みは、メモリへのランダム書き込みよりも効率的であり、Kafka のスループットを保証します)。 その構造は次のとおりです: server.properties/num.partitions は server.properties ファイル内の num.partitions 構成項目を表し、以下でも同様です。 パーティション内の各レコード (メッセージ) には、Offset、messageSize、Data の 3 つのプロパティが含まれます。 このうち、Offset はメッセージのオフセットを表します。 messageSize はメッセージのサイズを表します。データはメッセージの具体的な内容を表します。 パーティションはファイル形式でファイル システムに保存されます。場所は server.properties/log.dirs によって指定されます。命名規則は次のとおりです。 たとえば、トピック「page_visits」のメッセージは 5 つのパーティションに分割されており、そのディレクトリ構造は次のようになります。 パーティションは異なるブローカー上に配置できます。パーティションはセグメント化されており、各セグメントはセグメント ファイルです。 一般的なセグメント構成は次のとおりです。
パーティション ディレクトリには、データ ファイルとインデックス ファイルが含まれます。次の図は、パーティションのディレクトリ構造を示しています。 インデックスはスパース ストレージを使用します。メッセージごとにインデックスを作成するのではなく、インデックス ファイルが多くのスペースを占有しないように、特定のバイト数ごとにインデックスを作成します。 欠点は、インデックスなしのオフセットではメッセージの位置をすぐに特定できず、順次スキャンが必要になることですが、スキャン範囲は非常に狭くなります。 インデックスは、相対オフセットと位置という 2 つの部分 (どちらも 4 バイトの数値) で構成されます。 相対オフセットはセグメント ファイル内のオフセットを示し、位置はデータ ファイル内のメッセージの位置を示します。 概要: Kafka のメッセージ ストレージは、パーティション、ディスクの順次読み取りと書き込み、セグメンテーション (LogSegment)、およびスパース インデックスを使用して、高い効率を実現します。 パーティションとレプリカ トピックは物理的に複数のパーティションに分割され、異なるブローカー上に配置されます。レプリカがない場合、ブローカーがダウンすると、そのブローカー上のすべてのパーティションが利用できなくなります。 各パーティションには複数のレプリカ (server.properties/default.replication.factor に対応) を含めることができ、それらは異なるブローカーに割り当てられます。 読み取りと書き込みを担当し、プロデューサーとコンシューマーからのリクエストを処理するリーダーがいます。他のメンバーはフォロワーとして機能し、リーダーからメッセージを取得し、リーダーと同期を保ちます。 パーティションとレプリカをブローカーに割り当てる方法は?手順は次のとおりです。
上記の割り当てルールによれば、レプリカの数がブローカーの数より多い場合、同じブローカーに必ず 2 つの同一のレプリカが割り当てられ、冗長性が生じます。したがって、レプリカの数はブローカーの数以下である必要があります。 リーダー選挙 Kafka は、Zookeeper (/brokers/topics/[topic]/partitions/[partition]/state) で ISR (同期レプリカ) を動的に維持します。 ISR 内のすべてのレプリカがリーダーに「追いつき」、コントローラーは ISR から 1 つをリーダーとして選択します。 具体的なプロセスは以下のとおりです。
ISR が空の場合、レプリカ (必ずしも ISR メンバーではない) がリーダーとして選択されます。すべてのレプリカがダウンすると、いずれかのレプリカが復活してリーダーになります。 ISR (同期リスト) 内のフォロワーがリーダーに「追いつきました」。 「追いついた」というのは完全な一貫性を意味するものではありません。これは、server.properties/replica.lag.time.max.ms によって設定されます。 リーダーがフォロワーのメッセージの同期を待機する最大時間を示します。タイムアウトが発生した場合、リーダーはフォロワーを ISR から削除します。構成項目 replica.lag.max.messages が削除されました。 レプリカ同期 Kafka は「プル モード」を通じてメッセージを同期します。つまり、フォロワーは同期のためにリーダーからデータを一括してプルします。 具体的な信頼性はプロデューサーによって決定されます (構成項目 producer.properties/acks に基づきます)。 Kafka 0.9 では、プロデューサーの設定である request.required.acks=-1 が acks=all に置き換えられましたが、この古い設定はドキュメントに残っています。 バージョン 0.9 では、プロデューサー構成オプション request.required.acks=-1 は acks=all に置き換えられましたが、古い構成オプションはドキュメント内にまだ保持されています。 PS: 最新のドキュメント 2.2.x request.required.acks は存在しません。 Acks=-1 の場合、ISR が min.insync.replicas で指定された数より小さいと、NotEnoughReplicas または NotEnoughReplicasAfterAppend 例外がスローされます。 プロデューサーはどのようにメッセージを送信しますか? プロデューサーはまずメッセージを ProducerRecord インスタンスにカプセル化します。 メッセージルーティング:
メッセージはすぐには送信されず、まずシリアル化されて、上記のハッシュ関数である Partitioner に送信されます。パーティショナーがターゲット パーティションを決定した後、そのパーティションはメモリ バッファー (送信キュー) に送信されます。 プロデューサーの別の作業スレッド (つまり、送信スレッド) は、準備されたメッセージをバッファからリアルタイムで抽出し、バッチにカプセル化して、対応するブローカーに送信する役割を担います。 プロセスはおおよそ次のようになります。 画像は123archuより Consumer はどのようにしてメッセージを消費しますか? 各コンシューマーは論理コンシューマー グループに割り当てられます。パーティションは同じコンシューマー グループ内の 1 つのコンシューマーによってのみ消費されますが、異なるコンシューマー グループによって消費されることもあります。 トピックのパーティション数が p で、コンシューマー グループ内でこのトピックをサブスクライブしているコンシューマー数が c の場合、次のようになります。
リソースの不均衡を避けるために、コンシューマーとパーティションの数を合理的に割り当てる必要があります。パーティションの数がコンシューマーの数の整数倍である場合が最適です。 ①コンシューマーにパーティションを割り当てる方法 生成プロセス中、ブローカーはパーティションを割り当てる必要があり、消費プロセス中、パーティションはコンシューマーにも割り当てられる必要があります。 ブローカーがコントローラーを選択するのと同じように、コンシューマーもブローカーからコーディネーターを選択してパーティションを割り当てます。 コンシューマーの追加、コンシューマー (アクティブまたはパッシブ) の削減、パーティションの追加など、パーティションまたはコンシューマーの数が変更されると、再バランス調整が実行されます。 プロセスは次のとおりです。
②消費者フェッチメッセージ コンシューマーは「プル モード」を使用してメッセージを消費するため、コンシューマーは独自の消費動作を決定できます。 コンシューマーは Poll(duration) を呼び出してサーバーからメッセージを取得します。メッセージのプルの具体的な動作は、次の構成項目によって決まります。
パーティションでは、各メッセージにオフセットがあります。新しいメッセージはパーティションの末尾 (最新のセグメント ファイルの末尾) に書き込まれます。各パーティション上のメッセージは順番に消費され、異なるパーティション間のメッセージの消費順序は不確実です。 コンシューマーが複数のパーティションを消費する場合、パーティション間の消費順序は不確実ですが、各パーティションでは消費は順次行われます。 異なるコンシューマー グループの複数のコンシューマーが同じパーティションを消費する場合、各コンシューマーの消費は互いに影響を及ぼさず、各コンシューマーには独自のオフセットが存在します。 消費者 A と消費者 B は異なる消費者グループに属します。消費者 A はオフセット = 9 を読み取り、消費者 B はオフセット = 11 を読み取ります。この値は、次に読み取られる位置を示します。 つまり、コンシューマー A はオフセット 0 から 8 のメッセージを読み取り、コンシューマー B はオフセット 0 から 10 のメッセージを読み取りました。 次にコンシューマーがオフセット = 9 から読み取りを開始するときには、再バランスが発生する可能性があるため、コンシューマー A ではない可能性があります。 オフセットを保存するにはどうすればいいですか? コンシューマーがパーティションを消費する場合、現在の消費位置を記録するためにオフセットを保存する必要があります。 Offset は、自動的にコミットするか、Consumer の commitSync() または commitAsync() を呼び出して手動でコミットするかを選択できます。関連する構成は次のとおりです。
オフセットは、__consumeroffsets という名前のトピックに保存されます。メッセージを書き込むためのキーは、GroupId、Topic、Partition で構成され、値は Offset です。 一般に、各キーのオフセットはメモリにキャッシュされます。クエリを実行するときに、パーティションをトラバースする必要はありません。キャッシュがない場合、パーティションが最初に走査されてキャッシュが構築され、その後クエリが返されます。 __consumeroffsets のパーティション数は、次のサーバー構成によって決まります。
オフセットが保存されるパーティション、つまり __consumeroffsets のパーティション分割メカニズムは、次のように表現できます。
groupMetadataTopicPartitionCount は、上記で構成されたパーティションの数です。パーティションは同じコンシューマー グループ内の 1 つのコンシューマーによってのみ消費されるため、GroupId を使用して、このコンシューマーがオフセットを消費するパーティションを示すことができます。 メッセージング システムではどのような問題が発生する可能性がありますか? Kafka は 3 つのメッセージ配信セマンティクスをサポートしています。
データの取得 -> オフセットのコミット -> ビジネス処理
データの取得 -> ビジネス処理 -> オフセットのコミット。
① メッセージが繰り返し消費されないようにするにはどうすればよいでしょうか? (メッセージのべき等性) 更新操作の場合、べき等性は自然です。新しい操作の場合、処理前に各メッセージに一意の ID を与えて、処理済みかどうかを判断できます。この ID は Redis に保存でき、データベースに書き込まれる場合は主キー制約を使用できます。 ②メッセージ伝送の信頼性を確保するには? (メッセージ損失の問題) Kafka アーキテクチャによれば、メッセージが失われる可能性がある場所は、コンシューマー、プロデューサー、サーバーの 3 か所です。 コンシューマー側でデータが失われました: server.properties/enable.auto.commit が True に設定されている場合、Kafka は最初にオフセットをコミットしてからメッセージを処理します。このとき例外が発生すると、メッセージは失われます。 したがって、Offset の自動送信をオフにして、処理が完了した後に Offset を手動で送信することができます。これにより、メッセージが失われないことが保証されます。ただし、オフセットの送信が失敗すると、重複消費の問題が発生する可能性があります。この場合、べき等性が保証されます。 Kafka はメッセージを失います: ブローカーが誤ってクラッシュし、レプリカが 1 つしかない場合、ブローカー上のメッセージは失われます。 レプリカ>1 の場合、リーダーはフォロワーを新しいリーダーとして再選択します。フォロワーに同期されていないメッセージがある場合、それらのメッセージは失われます。 上記の問題を回避するには、次のように設定します。
プロデューサーがメッセージを失いました: 書き込みが成功したと見なされる前にすべての ISR がメッセージを同期するように、プロデューサー側で acks=all を設定します。 ③メッセージの順序をどうやって確保するか? Kafka のパーティション上のメッセージは連続しています。順番に消費する必要があるメッセージは、同じパーティションに送信され、単一のコンシューマーによって消費されます。 以上が私のカフカ研究の要約です。間違いや無理なところがありましたらご指摘ください! 参考文献:
著者:lbzhello プロフィール: Java プログラマー、メール: [email protected] |
>>: 伝統的な銀行はどのようにして小売業の変革の基盤を築くのでしょうか?
Budgetnode は設立されてから 1 年未満で、正式な登録資格を有する会社です。 budget...
Enterprise Management Associates (EMA) の最近の調査では、企業...
ウェブサイト構築・最適化業界は、第一に参入障壁が低く、第二に大量の人材が流入しているため、小規模なウ...
今日、厦門SEOはA5ウェブマスターのウェブサイトで記事を見ました。タイトルは「ウェブマスターはウェ...
企業がビジネスクリティカルなアプリケーションをクラウドで実行することに決めたら、他のプロバイダーに切...
5月16日、テンセントクラウドは同社の主要クラウド製品の数種類の値下げを発表し、一部の製品ラインでは...
この記事は、主に著者が所有するウェブサイトで発生した問題に対処するために書かれています。著者のウェブ...
今夜、湖南衛星テレビは、復活を期待しているテレビシリーズ「玄元剣」を放送します。このテレビシリーズは...
現実でも文学作品でも、私たちはみな人生の中で完璧な愛に出会うことを切望しています。中国のバレンタイン...
ヨーロッパカップが終盤を迎えようとしている。第1戦でもたらされた高い視聴率に加え、続く第1/4、第1...
KVM 仮想テクノロジの新バージョンを導入した VPS である directspace は、SSD ...
友人が私のブログにメッセージを残しました。「残念ながら、自分のセールスポイントをどうアピールすればい...
あらゆる Web テクノロジーの出現は、Web デザイナーやユーザーによりよいサービスを提供するため...
[[207661]] 1. 準備/opt/ディレクトリにモジュールとソフトウェアのフォルダを作成しま...
UK2グループ傘下の有名なVPSブランドであるvps.netが、全世界で約20のデータセンター+オン...