Kafka の優れた高性能設計 パート 2

Kafka の優れた高性能設計 パート 2

[[429455]]

みなさんこんにちは。私はウー兄弟です。

これは、「Mastering MQ Series」の第 2 部「Kafka の高パフォーマンス設計」です。前回の記事では、高性能設計の 2 つの重要な側面、つまり「Tao」として理解できるコンピューティングと IO について説明しました。同時に、カフカの高性能なデザインを俯瞰することができ、それは「芸術」として理解することができます。

図1: Kafkaの高性能設計の概要

この記事では、メッセージを保存および消費するための 8 つの高性能設計手法を 1 つずつ分析していきます。さっそく始めましょう。

1. メッセージ保存のパフォーマンス最適化方法

メッセージの保存はブローカーのコア機能です。使用される最適化方法は次の 4 つです。

1. IO多重化

Kafka ブローカーの場合、高いパフォーマンスを実現するために最初に考慮すべきことは、ブローカーとプロデューサーおよびコンシューマー間のメッセージ転送の問題を処理するための効率的なネットワーク通信モデルを設計することです。

まず、Kafka 2.8.0 ソース コードの SocketServer クラスにある重要なコメントを引用します。

このコメントを通じて、Kafka が非常に典型的な Reactor ネットワーク通信モデルを使用していることが実際にわかります。完全なネットワーク通信層フレームワーク図は次のとおりです。

図2: Kafkaネットワーク通信層のフレームワーク図

単純なメモリは 1 + N + M です。

  • 1: 1 つの Acceptor スレッドを示します。これは、新しい接続をリッスンし、新しい接続を Processor スレッドに渡して処理する役割を担います。
  • N: N 個のプロセッサ スレッドを表します。各プロセッサには独自のセレクタがあり、ソケットからのデータの読み取りと書き込みを担当します。
  • M: M 個の KafkaRequestHandler ビジネス処理スレッドを表します。これらのスレッドは、KafkaApis を呼び出してビジネス処理を実行し、応答を生成して Processor スレッドに渡します。

IO を研究した人なら、Reactor モードが従来の IO 多重化テクノロジを使用していることは明らかです。スレッドを再利用して多数のソケット接続を処理できるため、高いパフォーマンスが保証されます。 Netty と Redis が数十万、あるいは数百万もの同時接続を実現できるのはなぜでしょうか?実際、どちらも Reactor ネットワーク通信モデルを使用しています。

2. ディスクシーケンシャル書き込み

IO 多重化によるネットワーク通信が完了したら、ブローカーが次に考慮する必要があるのは、メッセージをすばやく保存する方法です。記事「Kafka ストレージ選択の秘密」では、Kafka がメッセージを保存するために「ログ ファイル」を使用することが述べられています。では、このディスク ファイル書き込み方法はどのようにして高いパフォーマンスを実現するのでしょうか?これらはすべてディスクの順次書き込みによるものです。それをどう理解すればいいのでしょうか?メッセージ キューとしての Kafka は、本質的には先入先出のキューであり、メッセージが生成されると不変になります。この秩序性と不変性により、Kafka はログ ファイルを順番に「書き込む」、つまり、ファイルの末尾にメッセージを追加するだけが可能になります。逐次書きを前提として、比較実験を見てみましょう。下の図から、ディスクのシーケンシャル書き込みのパフォーマンスはディスクのランダム書き込みよりもはるかに高く、メモリのランダム書き込みよりもさらに高いことがわかります。

図3: ディスクとメモリのIO速度の比較

その理由は非常に単純です。通常の機械式ディスクの場合、ランダム書き込み、つまりファイルの特定の場所を見つけてデータを書き込むだけの場合、パフォーマンスが非常に低くなります。しかし、シーケンシャルに書き込むと、ディスクのシークとディスクの回転にかかる時間が大幅に節約されるため、パフォーマンスが 3 桁向上します。

3. ページキャッシュ

ディスクのシーケンシャル書き込みはすでに非常に高速ですが、メモリのシーケンシャル書き込みに比べるとまだ数桁遅いです。さらに最適化することは可能ですか?答えはイエスです。

ここで Kafka はページ キャッシュ テクノロジーを使用します。簡単に言えば、オペレーティングシステム自体のキャッシュ技術を使用します。ディスク ログ ファイルの読み取りと書き込みを行う際、操作は実際にはメモリ上で実行され、その後、オペレーティング システムがページ キャッシュ内のデータを実際にディスクにフラッシュするタイミングを決定します。次の例の図はこれを明確に示しています。

図4: Kafkaのページキャッシュの原理

では、ページ キャッシュはいつ最も効果を発揮するのでしょうか?これには、ページ キャッシュで使用される 2 つの古典的な原則について言及する必要があります。ページ キャッシュは、最近アクセスされたデータが次にアクセスされる可能性が高いという原則に基づく「時間的局所性」の原則を使用して、最近使用されるディスク データをキャッシュします。ページ キャッシュに事前に読み込まれたディスク データは、データが継続的にアクセスされることが多いという事実に基づいて、「空間的局所性」の原則を利用します。メッセージ キューとして、Kafka はメッセージを順番に書き込み、コンシューマーがそれをすぐに読み取ります。これは間違いなく、上記の 2 つの局所性原則に準拠しています。そのため、ページ キャッシュは Kafka が高スループットを実現するための重要な要素の 1 つであると言えます。

さらに、ページ キャッシュにはもう 1 つの大きな利点があります。 Java を使用したことがある人なら誰でも、ページ キャッシュを使用せずに JVM プロセス内のキャッシュを使用すると、オブジェクトのメモリ オーバーヘッドが非常に大きくなる (通常は実際のデータ サイズの数倍、あるいはそれ以上になる) ことを知っています。さらに、ガベージコレクションが必要となり、GC によって発生する Stop The World 問題もパフォーマンスの問題を引き起こします。ページ キャッシュには明らかな利点があり、Kafka のコード実装が大幅に簡素化されることがわかります。

4. パーティションとセグメントの構造

ディスクのシーケンシャル書き込みとページ キャッシュを組み合わせることで、ログ ファイルの高パフォーマンスな読み取りと書き込みの問題が効果的に解決されます。ただし、トピックが 1 つのログ ファイルのみに対応する場合、トピックは 1 つのブローカー マシンにのみ保存できることは明らかです。膨大な量のメッセージに直面すると、単一のマシンのストレージ容量と読み取り/書き込みパフォーマンスは確実に制限されるため、別の独創的なストレージ設計、つまりストレージ用のデータをパーティション分割することが必要になります。私の記事「Kafka アーキテクチャ設計の Ren 子午線と Du 子午線」では、パーティションの概念と役割について詳しく説明しました。パーティションは Kafka の同時処理の最小粒度であり、ストレージのスケーラビリティの問題を非常にうまく解決します。パーティションの数が増えると、Kafka のスループットがさらに向上します。実際、Kafka の最下部のストレージ レイヤーには、パーティションの下に別のレイヤー、つまり「セグメンテーション」があります。簡単に理解すると、パーティションは実際にはフォルダーに対応し、セグメントは実際のログ ファイルに対応します。

図5: Kafkaパーティションセグメントストレージ

各パーティションは複数のセグメントに分割されます。では、パーティションの後にセグメントが必要なのはなぜでしょうか?

セグメントが導入されていない場合、1 つのパーティションは 1 つのファイルのみに対応し、ファイルは大きくなり続けるため、必然的に単一のパーティション ファイルが大きくなりすぎて、検索や保守が不便になります。また、履歴メッセージを削除する場合は、ファイルの以前の内容を削除する必要があります。ファイルが 1 つしかないということは、明らかに Kafka の順次書き込みの考え方に準拠していません。セグメントが導入された後は、古いセグメント ファイルを削除するだけで、各セグメントの順次書き込みが保証されます。

2. メッセージ消費のパフォーマンス最適化手法

Kafka は、100 万 TPS の書き込みパフォーマンスを実現するだけでなく、高性能なメッセージ読み取りの問題も解決する必要があり、そうでなければ高スループットとは言えません。次に、Kafka がメッセージを消費するときに使用する 4 つの最適化方法を見てみましょう。

1. スパースインデックス

読み取りパフォーマンスを向上させるにはどうすればよいでしょうか?インデックス作成は誰でも簡単に考えられます。 Kafka が直面するクエリ シナリオは実際には非常に単純です。オフセットまたはタイムスタンプに従ってメッセージを検索できます。 B-Tree インデックス構造を使用する場合、データが書き込まれるたびにインデックスを維持する必要があり (ランダム IO 操作)、また、「ページ分割」などの時間のかかる操作も発生します。単純なクエリ要件のみを実装する必要がある Kafka にとって、これらのコストは非常に大きくなります。したがって、B-Tree インデックスは Kafka には適していません。逆に、ハッシュ インデックスが適しているようです。読み取り操作を高速化するには、オフセットからログ ファイル オフセットへのマッピング関係をメモリ内で維持するだけでよい場合は、オフセットに基づいてメッセージを検索するたびに、ハッシュ テーブルからオフセットを取得してファイルを読み取ることができます。 (同じ考え方は、タイムスタンプに基づいてメッセージを検索するために使用できます) ただし、ハッシュ インデックスはメモリ内に常駐し、大量のデータを処理できないのは明らかです。 Kafka は 1 秒あたり数百万のメッセージを書き込む可能性があり、メモリが確実にバーストします。しかし、メッセージのオフセットは順序付けされるように設計できることがわかりました (実際には単調に増加する long 型のフィールドです)。そのため、メッセージはログ ファイル自体に順序どおりに格納されます。メッセージごとにハッシュインデックスを構築する必要はありません。メッセージを複数のブロックに分割し、各ブロックの最初のメッセージのオフセットのみをインデックスすることができます。まずサイズ関係に基づいてブロックを見つけ、次にブロック内を順番に検索します。これがKafkaの「スパースインデックス」の設計思想です。

図6: Kafkaのスパースインデックス設計

「スパース インデックス」の使用は、ディスク領域、メモリ領域、検索パフォーマンスなど、多くの面で妥協点として考えられます。スパース インデックスでは、オフセットが指定されると、Kafka はバイナリ検索を使用して、オフセットを超えない物理的な変位を効率的に特定し、ターゲット メッセージを検索します。

2. mmap

スパース インデックスの使用により、効率的なクエリの問題は基本的に解決されましたが、このプロセスにはさらなる最適化の余地が残されています。つまり、上記のスパース インデックス ファイルを mmap (メモリ マップ ファイル) を介して読み書きし、メッセージのクエリ速度をさらに向上させる必要があります。

  • 注意: mmap とページ キャッシュは 2 つの異なる概念であり、多くのオンライン資料ではこれらが混同されています。さらに、Kafka はログファイルを読み取るときにも mmap を使用することを記載したドキュメントもあります。バージョン 2.8.0 のソースコード分析により、この情報も間違っていることがわかりました。実際には、インデックス ファイルの読み取りと書き込みにのみ mmap が使用されます。

mmap を理解するにはどうすればいいですか?前述したように、従来のファイル操作では、ページ キャッシュ メカニズムを使用して読み取りと書き込みのパフォーマンスが向上します。ただし、ページ キャッシュはカーネル空間にあり、ユーザー プロセスが直接アクセスすることはできないため、ファイルを読み取るときには、ページ キャッシュ内のデータを再度ユーザー空間にコピーするためのシステム コールが必要になります。 mmap を使用すると、ディスク ファイルがプロセスの仮想アドレスにマップされ、システム コールや追加のメモリ コピー オーバーヘッドが発生しなくなるため、ファイルの読み取り効率が向上します。

図 7: mmap 図、「Coder's Desert Island Survival」より引用

mmap に関しては、私の親友 Xiaofeng が非常に人気のある記事を書きました: mmap を使用すると、プログラマーはどのようなクールな操作をアンロックできるのでしょうか?参考にしていただけます。具体的には、Kafka ソース コード レベルでは、JDK nio パッケージの MappedByteBuffer のマップ関数に基づいて、ディスク ファイルをメモリにマップします。ログファイルで mmap が使用されないのはなぜでしょうか?これは実は非常に良い質問です。コミュニティはこの質問に対して公式の回答を出していないため、インターネット上の回答では作者の意図について推測することしかできません。私は個人的に、stackoverflow のこの回答に同意します:

mmap によってメモリにマップできるバイト数は、アドレス空間によって異なります。 32 ビット アーキテクチャでは、4 GB 以下のファイルしか処理できません。 Kafka ログは、一度に一部しかマップできないほど大きい場合が多く、読み取りが非常に複雑になります。ただし、インデックス ファイルはまばらで、比較的小さいです。これらをメモリにマップすると、検索プロセスが高速化されます。これがメモリ マップ ファイルによってもたらされる主な利点です。

3. ゼロコピー

スパース インデックスを使用してメッセージが照会された後、次のステップは、ディスク ファイルからメッセージを読み取り、ネットワーク カードを介してコンシューマーに送信することです。このステップをどのように最適化できますか? Kafka はパフォーマンスを向上させるためにゼロコピー テクノロジーを使用します。いわゆるゼロ コピーとは、アプリケーションを経由せずにディスク ファイルからネットワーク カード デバイスにデータが直接コピーされ、カーネルとユーザー モード間のコンテキスト切り替えが削減されることを意味します。

以下のプロセスは、ゼロコピー技術を使用しない場合に、ディスクからファイルを読み取り、ネットワーク カードを介して送信するプロセスです。 4 つのコピーと 4 つのコンテキスト スイッチが実行されていることがわかります。

図8: 非ゼロコピー技術のフローチャート(「艾小仙」より引用)

ゼロコピー技術(sendfile メソッドを通じて最下層に実装)を使用する場合、プロセスは次のようになります。ご覧のとおり、必要なのは 3 つのコピーと 2 つのコンテキスト スイッチだけであり、明らかにパフォーマンスが向上します。

図9: ゼロコピー技術のフローチャート(「艾小仙」より引用)

4. バッチプル

プロデューサーがメッセージをバッチで送信するのと同様に、メッセージ コンシューマーもメッセージをバッチでプルし、一度に 1 つのメッセージ セットをプルします。これにより、ネットワーク転送のオーバーヘッドが大幅に削減されます。さらに、Kafka の優れた高性能設計 (パート 1) で紹介したように、プロデューサーは実際にクライアント側でバッチ メッセージを圧縮します。これらのメッセージのバッチがブローカーに永続化されるとき、それらは圧縮されたままであり、最終的にコンシューマー側で解凍されます。

3. 最後に

以上が、Kafka の 12 の高性能設計手法の詳細な説明です。これら 2 つの記事では、まず IO とコンピューティングという 2 つの側面からマクロなアプローチを取り、次に MQ の 1 回の送信、1 回のストレージ、1 回の消費のコンテキストに沿って、ミクロの観点から Kafka の高パフォーマンスの全体像を分析します。 Kafka は、高性能設計の教科書的な例であると言えます。 Prodcuer から Broker、そして Consumer に至るまで、細部に至るまで慎重に最適化し、最終的に単一のマシンで毎秒数十万 TPS という究極のパフォーマンスを実現しました。

最後に、この記事の分析手法が他の高性能ミドルウェアの理解に役立つことを願っています。ウー兄弟です。また次回お会いしましょう!

<<:  マジック: メモリプーリングと分散 AI クラスターの最適化

>>:  おすすめする価値のある Kubernetes ダッシュボード ツール トップ 9

推薦する

Kubernetes クラスター リソースをクリーンアップするためによく使用されるコマンド

[[442097]]長時間実行されるクラスターでは、さまざまなリソース枯渇の問題が発生することがよく...

VMware が vSphere 6 の標準サポートを終了。何をするか

2020 年 3 月、VMware は vSphere 6.0 の標準サポートを終了しました。多くの...

「江南スタイル」の人気からマーケティング手法を分析

最近人気の「江南スタイル」は「世界の神曲」と称賛されている。70代の老人から3歳の子供まで、「江南ス...

情報化時代において、私たちは多様な思考に直面して利己的な世界から抜け出さなければならない。

時代の発展とともに、インターネットが世界を覆い、情報量が飛躍的に増加し、人々はさまざまな情報を便利か...

CloudOps: クラウド運用を最適化するための新しいフレームワーク

翻訳者 |李睿校正:孫淑娟クラウド コンピューティング戦略のアップグレードを検討している企業は、クラ...

クラウドネイティブとKubernetesがアプリケーション開発を簡素化する方法

「クラウド コンピューティング」は、現在のテクノロジーについて語るときに非常に一般的になりつつあり、...

1ヶ月以内にキーワードをホームページに載せる体験談

実際、私は長い間SEOと連絡を取りました(登録時間2009-3-5)。オンラインで1か月もかかりませ...

Alexaを通じてユーザーのニーズを分析し、ユーザーエクスペリエンスを向上させる

Baidu アルゴリズムの更新により、ユーザー エクスペリエンスの問題にますます注目が集まっています...

layer.ae はどうですか?米国データセンターの高性能AMD RyzenシリーズVPSのレビュー

layer.aeは、米国西海岸のワシントン州スポケーンにVPS事業を展開しています。米国西海岸は中国...

NetEase、海外のbit.lyに似た短縮アドレスサービス126.amを開始

【捜狐ITニュース】(文/何鋒)網易は6月5日、海外で人気のbit.lyに似たURL短縮サービス「網...

アプリプロモーションで高品質なチャンネルを見極める5つの方法

前回の記事「アプリプロモーションで200以上のチャンネルを見つける方法」では、チャンネルを見つける方...

SEOにおける「サブドメインとディレクトリ」の違い

サブドメインとディレクトリに関しては、多くの人がそれらの違いを知らず、いつサブドメインを使用し、いつ...

ガートナーは、2021年に世界のパブリッククラウド支出が18%増加すると予測している

ガートナーの予測によると、パブリッククラウドサービスに対する世界のエンドユーザーの支出は、2020年...

VMware と China Mobile が企業のクラウド移行を加速する次世代クラウド デスクトップを発表

[51CTO.com からのオリジナル記事] VMware は 11 月 16 日、China Mo...

リンク交換の基本原則と戦略

(1)競合他社へのリンクGoogleやBaiduなどの大手検索エンジンを見ると、単に「被リンク」だけ...