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