私は最近、Kafak のソース コードをいくつか研究し、Kafak の改良されたバイナリ検索アルゴリズムを皆さんと共有したいと思います。バイナリ検索はすべてのプログラマーが習得すべき基本的なアルゴリズムであり、Kafka がバイナリ検索をどのように改善して独自のシナリオに適用するかを学ぶことは価値があります。 Kafka はインデックス検索シナリオにバイナリ検索を適用するため、この記事ではまず Kafka のログ構造とインデックスについて簡単に紹介します。 Kafak では、メッセージはログの形式で保存されます。各ログは、実際には複数のログ セグメントを含むフォルダーです。ログ セグメントとは、次の図に示すように、メッセージ ログ ファイルと、同じファイル名 (開始オフセット) を持つ 4 つのインデックス ファイルを指します。 メッセージはメッセージ ログ ファイルに追加形式で保存され、各メッセージには一意のオフセットがあります。メッセージを検索する場合、インデックス ファイルを使用して検索します。クエリがオフセットに基づいている場合、メッセージの検索にはオフセット インデックス ファイルが使用されます。インデックスクエリの議論を容易にするために、以下の議論は変位インデックスの背景に基づいて行われます。変位インデックスの本質は、オフセットと対応するディスクの物理的な位置を格納するバイト配列です。ここで、オフセットとディスクの物理的な位置は 4 バイトに固定されており、次の図に示すように、8 バイトごとにキーと値のペアとして考えることができます。 インデックス構造を明確に理解できたので、この記事のテーマである「バイナリ検索」に正式に進むことができます。インデックス項目の配列とターゲット オフセットを指定すると、次のコードを記述できます。
上記のコードでは、通常のバイナリ検索を使用しています。これがどのような問題を引き起こす可能性があるか見てみましょう。各インデックス項目のサイズは 4B ですが、オペレーティング システムがメモリにアクセスする最小単位はページです。ページは通常 4KB (4096B) で、512 個のインデックス項目が含まれます。インデックス内の指定されたオフセットを見つけることは、オペレーティング システムがメモリにアクセスしたときに指定されたオフセットが配置されているページを見つけることになります。次の図に示すように、インデックス サイズが 13 ページであると仮定します。 Kafka は通常、メッセージを読み取るときに最新のオフセットを読み取るため、クエリされるページは末尾、つまりページ 12 に集中します。次に、上記のコードを組み合わせて、最新のオフセットをクエリするときにどのページにアクセスされるかを確認します。バイナリ検索によれば、ページ 6、9、11、12 が順番に訪問されます。 Kafka が受信するメッセージ数が増えると、インデックス ファイルも 13 ページまで増加します。このとき、バイナリ検索に従って、7、10、12、13 ページが順番にアクセスされます。 訪問したページが前のページとは全く異なっていることがわかります。以前は、ページが 12 しかなかったため、Kafka はインデックスを読み取るときにページ 6、9、11、12 に頻繁にアクセスしていました。ただし、Kafka は速度を上げるために mmap を使用するため、すべての読み取りおよび書き込み操作はオペレーティング システムのページ キャッシュを経由するため、ページ 6、9、11、および 12 はディスクの読み込みを回避するためにページ キャッシュにキャッシュされます。ただし、ページ 13 を増やすと、ページ 7、10、12、13 にアクセスする必要があります。ページ 7 と 10 は長い間アクセスされていないため (最近のオペレーティング システムではページ キャッシュの管理に LRU またはその派生形式が使用されています)、ページ キャッシュ外になっている可能性があり、ページ フォールト割り込みが発生します (スレッドは、ページ キャッシュにキャッシュされていないディスクからのデータの読み込みを待機してブロックされます)。 Kafka の公式テストでは、この状況により数ミリ秒から 1 秒の範囲の遅延が発生します。 上記の状況を考慮して、Kafka はバイナリ検索を改良しました。通常、データはインデックスの末尾から読み取られます。次に、インデックスの最後の 8192B (8KB) を「ホット ゾーン」に、残りを「コールド ゾーン」に分割し、それぞれに対してバイナリ検索を実行します。コードは次のように実装されます。
これの利点は、テールが頻繁にクエリされる場合、テール ページは基本的にページ キャッシュ内にあるため、ページ フォールトによる中断を回避できることです。 前の例を使って見てみましょう。各ページには最大 512 個のインデックス項目が含まれるため、最後の 1024 個のインデックス項目を含むページはホット領域と見なされます。次に、ページ 12 がいっぱいでない場合は、ページ 10、11、および 12 がホット エリアであると判断されます。ページ 12 がちょうどいっぱいになると、ページ 11 と 12 がホット エリアであると判断されます。ページ 13 が増加していっぱいでない場合は、ページ 11、12、および 13 がホット領域であると判断されます。最新のメッセージを読んでいると仮定すると、ホットゾーンでのバイナリ検索は次のようになります。 ページ 12 がいっぱいでない場合は、ページ 11 と 12 が順番にアクセスされます。ページ 12 がいっぱいになると、アクセスしたページにも同じ状況が適用されます。ページ 13 が表示されると、ページ 12 とページ 13 が順番にアクセスされ、長時間アクセスされていないページにはアクセスされなくなるため、ページ フォールトによる中断を効果的に回避できます。 ホットゾーンのサイズが 8192 バイトに設定されている理由については、公式の説明では、これが適切な値であるということになります。 ホット ゾーン内のページ数が 3 以下になるように十分小さい場合、バイナリ検索で使用されるページはページ キャッシュ内にある可能性が高くなります。つまり、設定値が大きすぎると、ホットゾーンのページがページ キャッシュに含まれなくなる可能性があります。 これは、4MB のメッセージ データをカバーするのに十分な大きさ (8192 バイト、または変位インデックスの場合は 1024 個のインデックス エントリ) であり、ほとんどの同期ノードがホット ゾーンでクエリを実行するのに十分です。 最後に一言でまとめると、Kafka インデックスで通常のバイナリ検索を使用すると、ページ欠落の中断が発生し、遅延が発生します。また、ほとんどのクエリが末尾に集中するため、インデックス領域をホット領域とコールド領域に分割し、別々に検索することで、ホット領域のページが可能な限りページキャッシュ内にあるようにすることができ、ページ欠落による中断を回避することができます。 |
<<: Scality: コンテナ化とクラウドネイティブアプリケーションが2021年のデータストレージ環境を定義する
gigsgigscloud は昨日、まったく新しいシンガポール VPS とシンガポール クラウド サ...
2018年最もホットなプロジェクト:テレマーケティングロボットがあなたの参加を待っていますA5ベンチ...
以前、この VPS について記事を公開しました: bluevm - 4g メモリ/100g ハードド...
物語はここから始まる。「 adman:新年50%オフ、ロシア極東ノボシビルスク、VPS、独立サーバー...
[[378938]] 1. はじめに前回の記事では、AuthenticationManager の初...
ウェブサイトのユーザー エクスペリエンスは、アート、デザイン、プログラミング、戦略、フィードバックを...
2018年最もホットなプロジェクト:テレマーケティングロボットがあなたの参加を待っています近年、Go...
先日、「SAP寧波スマート製造サミット」が盛大に開催されました。サミットでは、SAPと寧波市北侖区人...
最近、buyvm の VPS と比較しました。AMD Ryzen 9 3900X+DDR4+SSD ...
Weiboでは、一部の企業や個人が、より良いマーケティング成果を達成し、より多くの人々の注目を集める...
2020年7月20日、Huawei CloudはTechWaveテクノロジーサミットを開催しました。...
K8s は、コンテナ化されたアプリケーションの展開、スケーリング、管理を自動化するオープンソースのコ...
Docker入門Docker は、コンテナ内でアプリケーションを構築、デプロイ、実行するためのオープ...
A2hosting、ブラックフライデーがやって来ました! SSD ハード ドライブを搭載した仮想ホス...
1. テンセントとJDの取引の余波:Yixunは死んだテンセントとJD.comの取引がまだ噂の段階だ...