sql >> データベース >  >> NoSQL >> HBase

HBase BlockCache 101

    このブログ投稿は、Clouderaとの統合前にHortonworks.comで公開されていました。一部のリンク、リソース、または参照は、正確でなくなる可能性があります。

    このブログ投稿は元々ここに表示されていましたが、完全にここに複製されています。

    HBaseは、順序付けられた書き込みログとログ構造化されたマージツリーのコアコンセプトに基づいて構築された分散データベースです。他のデータベースと同様に、最適化されたI/OはHBaseにとって重要な関心事です。可能な場合は、I/Oをまったく実行しないことが優先されます。これは、メモリ使用率とキャッシュ構造が最も重要であることを意味します。この目的のために、HBaseは「メモリストア」と「ブロックキャッシュ」の2つのキャッシュ構造を維持しています。 MemStoreとして実装されたメモリストア 、受信時にデータ編集を蓄積し、メモリにバッファリングします(1)。ブロックキャッシュ、 BlockCacheの実装 インターフェイス。データブロックは、読み取られた後もメモリ内に常駐します。

    MemStore 最近の編集にアクセスするために重要です。 MemStoreなし 、書き込みログに書き込まれたデータにアクセスするには、少なくとも O(n)で、そのファイルからエントリを読み取り、逆シリアル化する必要があります。 手術。代わりに、 MemStore O(log n)を楽しむスキップリスト構造を維持します アクセスコストがかかり、ディスクI/Oは必要ありません。 MemStore ただし、HBaseに保存されているデータのごく一部が含まれています。

    BlockCacheからの読み取りのサービス は、HBaseがミリ秒の遅延でランダム読み取りを提供できる主要なメカニズムです。データブロックがHDFSから読み取られると、 BlockCacheにキャッシュされます。 。隣接するデータ(同じブロックからのデータ)の後続の読み取りでは、ディスクからそのデータを再度取得するというI / Oペナルティは発生しません(2)。 BlockCache それがこの投稿の残りの焦点になります。

    キャッシュするブロック

    BlockCacheを理解する前に 、HBaseの「ブロック」が正確に何であるかを理解するのに役立ちます。 HBaseコンテキストでは、ブロックはI/Oの単一ユニットです。 HFileにデータを書き込む場合、ブロックは書き込まれるデータの最小単位です。同様に、単一のブロックは、HBaseがHFileから読み戻すことができるデータの最小量です。 HBaseブロックをHDFSブロック、または基盤となるファイルシステムのブロックと混同しないように注意してください。これらはすべて異なります(3)。

    HBaseブロックには、 DATAの4種類があります。 、 META INDEX 、および BLOOM

    DATA ブロックはユーザーデータを保存します。 BLOCKSIZE 列ファミリーに指定されている場合、これはこの種のブロックのヒントです。念のために言っておきますが、それは単なるヒントです。 MemStoreをフラッシュしている間 、HBaseは、このガイドラインを尊重するために最善を尽くします。各セルの後 が書き込まれると、ライターは書き込まれた量が>=ターゲットのBLOCKSIZEであるかどうかを確認します 。その場合、現在のブロックを閉じて次のブロックを開始します(4)。

    INDEX およびBLOOM ブロックは同じ目的を果たします。どちらも読み取りパスを高速化するために使用されます。 INDEX ブロックは、 Cellのインデックスを提供します s DATAに含まれている ブロック。 BLOOM ブロックには、同じデータに対するブルームフィルターが含まれています。インデックスを使用すると、読者は Cellの場所をすばやく知ることができます。 保存する必要があります。フィルタは、 Cellがいつになるかを読者に通知します 間違いなくデータに含まれていません。

    最後に、 META ブロックには、HFile自体に関する情報やその他のさまざまな情報(メタデータ)が格納されます。 HFile形式とさまざまなブロックタイプの役割のより包括的な概要は、Apache HBase I / O –HFileに記載されています。

    HBaseBlockCacheとその実装

    BlockCacheが1つあります リージョンサーバーのインスタンス。これは、そのサーバーによってホストされているすべてのリージョンのすべてのデータが同じキャッシュプールを共有することを意味します(5)。 BlockCache リージョンサーバーの起動時にインスタンス化され、プロセスの存続期間全体にわたって保持されます。従来、HBaseは単一の BlockCacheのみを提供していました 実装: LruBlockCache 。 0.92リリースでは、HBASE-4027の最初の代替手段である SlabCacheが導入されました。 。 HBase 0.96では、HBASE-7404を介して、 BucketCacheと呼ばれる別のオプションが導入されました。 。

    実証済みのLruBlockCacheの主な違い そして、これらの選択肢は、メモリを管理する方法です。具体的には、 LruBlockCache は完全にJVMヒープ上に存在するデータ構造ですが、他の2つはJVMヒープの外部からメモリを利用できます。 JVMヒープメモリはJVMガベージコレクタによって管理されますが、他のメモリは管理されないため、これは重要な違いです。 SlabCacheの場合 およびBucketCache 、アイデアは、ヒープに保持されるオブジェクトの数を減らすことによって、リージョンサーバープロセスが経験するGCプレッシャーを減らすことです。

    LruBlockCache

    これはデフォルトの実装です。データブロックは、この実装を使用してJVMヒープにキャッシュされます。これは、シングルアクセス、マルチアクセス、およびインメモリの3つの領域に細分されます。エリアのサイズは、 BlockCache 全体の25%、50%、25%です。 それぞれサイズ(6)。 HDFSから最初に読み取られたブロックは、シングルアクセス領域に配置されます。連続アクセスは、そのブロックをマルチアクセスエリアに昇格させます。メモリ内領域は、 IN_MEMORYとしてフラグが付けられた列ファミリからロードされたブロック用に予約されています 。エリアに関係なく、Least-Recently-Usedアルゴリズム、つまり「LruBlockCache」の「Lru」を使用して、新しいブロック用のスペースを確保するために古いブロックが削除されます。

    SlabCache

    この実装では、 DirectByteBuffer を使用して、JVMヒープの外部にメモリ領域を割り当てます。 s。これらの領域は、この BlockCacheの本体を提供します 。特定のブロックが配置される正確な領域は、ブロックのサイズに基づいています。デフォルトでは、2つの領域が割り当てられ、構成されたオフヒープキャッシュサイズの合計のそれぞれ80%と20%を消費します。前者は、ほぼターゲットブロックサイズであるブロックをキャッシュするために使用されます(7)。後者は、ターゲットブロックサイズの約2倍のブロックを保持します。ブロックは、それが収まる最小の領域に配置されます。キャッシュがいずれかの領域に収まるよりも大きいブロックに遭遇した場合、そのブロックはキャッシュされません。 LruBlockCacheのように 、ブロックエビクションはLRUアルゴリズムを使用して管理されます。

    BucketCache

    この実装は、次の3つの異なるモードのいずれかで動作するように構成できます。 heap offheap 、および file 。動作モードに関係なく、 BucketCache キャッシュされたブロックを保持するための「バケット」と呼ばれるメモリ領域を管理します。各バケットは、ターゲットブロックサイズで作成されます。 ヒープ 実装により、JVMヒープ上にこれらのバケットが作成されます。 offheap 実装ではDirectByteByffersを使用します JVMヒープの外部でバケットを管理するため。 ファイル modeは、バケットが作成されるファイルシステム上のファイルへのパスを想定しています。 ファイル モードは、低遅延のバッキングストア(メモリ内ファイルシステム、またはSSDストレージにあるファイル)での使用を目的としています(8)。モードに関係なく、 BucketCache 異なるサイズの14個のバケットを作成します。 LruBlockCache と同様に、ブロックアクセスの頻度を使用して使用率を通知します 、および25%、50%、25%の同じシングルアクセス、マルチアクセス、およびメモリ内の内訳があります。また、デフォルトのキャッシュと同様に、ブロックエビクションはLRUアルゴリズムを使用して管理されます。

    マルチレベルキャッシング

    両方のSlabCache およびBucketCache マルチレベルのキャッシュ戦略の一部として使用するように設計されています。したがって、全体の BlockCacheの一部 サイズはLruBlockCacheに割り当てられます 実例。このインスタンスは第1レベルのキャッシュ「L1」として機能し、もう一方のキャッシュインスタンスは第2レベルのキャッシュ「L2」として扱われます。ただし、 LruBlockCache間の相互作用 およびSlabCache LruBlockCacheとは異なります およびBucketCache 相互作用します。

    SlabCache DoubleBlockCacheと呼ばれる戦略 は、常にL1キャッシュとL2キャッシュの両方にブロックをキャッシュすることです。 2つのキャッシュレベルは独立して動作します。ブロックを取得するときに両方がチェックされ、それぞれが他方に関係なくブロックを削除します。 BucketCache CombinedBlockCacheと呼ばれる戦略 、BloomおよびIndexブロック専用のL1キャッシュを使用します。データブロックはL2キャッシュに直接送信されます。 L1ブロックが完全に破棄されるのではなく、削除された場合、そのブロックはL2キャッシュに降格されます。

    どちらを選択しますか?

    代替のBlockCacheの1つを有効にすることを検討する理由は2つあります。 実装。 1つ目は、リージョンサーバー専用のRAMの量です。コミュニティの知恵は、リージョンサーバーに関する限り、JVMヒープの上限が14GBから31GBの間であることを認識しています(9)。正確な制限は通常、ハードウェアプロファイル、クラスター構成、データテーブルの形状、およびアプリケーションアクセスパターンの組み合わせによって異なります。 GCが一時停止し、 RegionTooBusyException が発生すると、危険ゾーンに入ったことがわかります。 sログの氾濫を開始します。

    代替キャッシュを検討するもう1つの時期は、応答の待ち時間が本当に 重要です。ヒープを約8〜12 GBに抑えると、CMSコレクターが非常にスムーズに実行され(10)、応答時間の99パーセンタイルに測定可能な影響があります。この制限を考えると、唯一の選択肢は、代替のガベージコレクターを探索するか、これらのオフヒープ実装の1つをスピンすることです。

    この2番目のオプションは、まさに私が行ったことです。次の投稿では、さまざまな BlockCache の応答時間を比較する、非科学的ですが有益な実験結果をいくつか共有します。 実装。

    いつものように、ご期待ください。HBaseを使い続けてください!

    1: MemStore 受信時にデータ編集を蓄積し、メモリにバッファリングします。これには2つの目的があります。1回の操作でディスクに書き込まれるデータの総量を増やすことと、メモリ内の最近の変更を保持して、低遅延の読み取りの形で後続のアクセスを行うことです。前者は、HBase書き込みチャンクをHDFSブロックサイズとほぼ同期させ、HBaseアクセスパターンを基盤となるHDFSストレージと整合させるために重要です。後者は自明であり、最近書き込まれたデータへの読み取り要求を容易にします。この構造はデータの耐久性に関与していないことを指摘しておく価値があります。編集内容は、順序付けられた書き込みログである HLogにも書き込まれます。 、これには、構成可能な間隔で、通常は即時にHDFS追加操作が含まれます。

    2:ローカルファイルシステムからデータを再読み込みするのが最良のシナリオです。結局のところ、HDFSは分散ファイルシステムであるため、最悪の場合、ネットワークを介してそのブロックを読み取る必要があります。 HBaseは、データの局所性を維持するために最善を尽くします。これらの2つの記事では、HBaseにとってデータの局所性が何を意味するのかとその管理方法について詳しく説明しています。

    3:ファイルシステム、HDFS、およびHBaseブロックはすべて異なりますが、関連しています。最新のI/Oサブシステムは、抽象化の上に多くの抽象化レイヤーがあります。その抽象化の中核となるのは、「ブロック」と呼ばれる単一のデータ単位の概念です。したがって、これら3つのストレージレイヤーはすべて、それぞれ独自のサイズの独自のブロックを定義します。一般に、ブロックサイズが大きいほど、シーケンシャルアクセスのスループットが向上します。ブロックサイズを小さくすると、ランダムアクセスが高速になります。

    4: BLOCKSIZEを配置する データが書き込まれた後のチェックには2つの影響があります。単一のセル DATAに書き込まれるデータの最小単位です ブロック。 Cellも意味します 複数のブロックにまたがることはできません。

    5:これは MemStoreとは異なります 、リージョンサーバーによってホストされるリージョンごとに個別のインスタンスがあります。

    6:ごく最近まで、これらのメモリパーティションは静的に定義されていました。 25/50/25の分割を無効にする方法はありませんでした。特定のセグメント、たとえばマルチアクセスエリアは、他のエリアが十分に活用されていない限り、50%の割り当てよりも大きくなる可能性があります。他のエリアでの使用率が上がると、25/50/25のバランスが達成されるまで、マルチアクセスエリアからエントリが削除されます。オペレーターはこれらのデフォルトサイズを変更できませんでした。 HBase 0.98.0で出荷されるHBASE-10263では、これらのサイズの構成パラメーターが導入されています。柔軟な動作が維持されます。

    7:「おおよその」ビジネスは、ブロックサイズでいくらかの小刻みに動く部屋を許可することです。 HBaseブロックサイズは大まかなターゲットまたはヒントであり、厳密に強制された制約ではありません。特定のデータブロックの正確なサイズは、ターゲットブロックのサイズとセルのサイズによって異なります。 そこに含まれる値。ブロックサイズのヒントは、デフォルトのブロックサイズである64kbとして指定されています。

    8: BucketCacheを使用する file 永続的なバッキングストアを備えたモードには、永続性というもう1つの利点があります。起動時に、キャッシュ内の既存のデータを検索し、その有効性を確認します。

    9:私が理解しているように、この範囲の上限をアドバイスする2つの要素があります。 1つは、JVMオブジェクトのアドレス指定可能性の制限です。 JVMは、完全な64ビットのネイティブアドレスではなく、32ビットの相対アドレスを使用してヒープ上のオブジェクトを参照できます。この最適化は、ヒープの合計サイズが32GB未満の場合にのみ可能です。詳細については、CompressedOopsをご覧ください。 2つ目は、システム内のオブジェクトチャーンの量に対応するガベージコレクターの機能です。私の知る限り、オブジェクトチャーンの3つのソースは、 MemStoreです。 、 BlockCache 、およびネットワーク操作。 1つ目は、 MemSlabによって軽減されます。 機能。デフォルトで有効になっています。 2つ目は、データセットのサイズとキャッシュのサイズの影響を受けます。 3つ目は、HBaseがデータコピーに依存するネットワークスタックを利用している限り、仕方がありません。

    10:8と同様に、これは「最新のハードウェア」を想定しています。ここでのやり取りは非常に複雑で、単一のブログ投稿の範囲をはるかに超えています。


    1. Spring-MongoDb集約フレームワークで$cond操作を使用する方法

    2. Redis:AmazonEC2とElasticache

    3. Springブートスターターデータの残り、@Notnull制約が機能しない

    4. スキーマがマングース配列にデフォルト値を追加しないのはなぜですか?