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

Apache HBase I / O – HFile

    はじめに

    Apache HBaseは、ランダムに最適なHadoopオープンソース、分散、バージョン管理されたストレージマネージャーです。 、リアルタイム読み取り/書き込み アクセス。

    待って待って?ランダムなリアルタイムの読み取り/書き込みアクセス?
    それはどのように可能ですか? Hadoopは、単なるシーケンシャルな読み取り/書き込みのバッチ処理システムではありませんか?

    はい、同じことについて話しています。次の数段落で、HBaseがランダムI / Oを実現する方法、データを保存する方法、HBaseのHFile形式の進化について説明します。

    Apache Hadoop I/Oファイル形式

    Hadoopには、キーと値のペアを追加するために使用できるSequenceFile [1]ファイル形式が付属していますが、hdfsの追加のみの機能により、ファイル形式では挿入された値の変更または削除を許可できません。許可される操作は追加のみです。指定されたキーを検索する場合は、キーが見つかるまでファイルを読み通す必要があります。

    ご覧のとおり、シーケンシャルな読み取り/書き込みパターンに従う必要があります…しかし、この上にHBaseのようなランダムで低レイテンシの読み取り/書き込みアクセスシステムを構築するにはどうすればよいでしょうか。

    この問題を解決するために、HadoopにはSequenceFileの拡張であるMapFile[1]と呼ばれる別のファイル形式があります。 MapFileは、実際には、データファイル「/data」とインデックスファイル「/index」の2つのSequenceFileを含むディレクトリです。 MapFileを使用すると、ソートされたキーと値のペアを追加し、N個のキー(Nは構成可能な間隔)ごとにキーとオフセットをインデックスに格納できます。これにより、すべてのレコードをスキャンする代わりに、エントリの少ないインデックスをスキャンするため、非常に高速なルックアップが可能になります。ブロックを見つけたら、実際のデータファイルにジャンプできます。

    MapFileは、キーと値のペアをすばやく検索できるので便利ですが、それでも2つの問題があります。

    • キー/値を削除または置換するにはどうすればよいですか?
    • 入力が並べ替えられていない場合、MapFileを使用できません。

    HBase&MapFile

    HBaseキーは、行キー、列ファミリー、列修飾子、タイムスタンプ、およびタイプで構成されます。

    キーと値のペアを削除する問題を解決するには、「タイプ」フィールドを使用してキーを削除済みとしてマークします(トゥームストーンマーカー)。キーと値のペアを置き換える問題を解決するには、後のタイムスタンプを選択するだけです(正しい値はファイルの終わり近くにあり、追加のみは最後に挿入されたものが終わり近くにあることを意味します)。

    「順序付けされていない」キーの問題を解決するために、最後に追加されたキー値をメモリに保持します。しきい値に達すると、HBaseはそれをMapFileにフラッシュします。このようにして、ソートされたキー/値をMapFileに追加することになります。

    HBaseはまさにこれを行います[2]:table.put()を使用して値を追加すると、キー/値がMemStoreに追加されます(内部では、MemStoreはソートされたConcurrentSkipListMapです)。 memstoreごとのしきい値(hbase.hregion.memstore.flush.size)に達するか、RegionServerがmemstore(hbase.regionserver.global.memstore.upperLimit)に大量のメモリを使用している場合、データは新しいMapFileとしてディスクにフラッシュされます。 。

    各フラッシュの結果は新しいMapFileであり、これは、キーを見つけるために複数のファイルを検索する必要があることを意味します。これはより多くのリソースを必要とし、潜在的に遅くなります。

    getまたはscanが発行されるたびに、HBaseは各ファイルをスキャンして結果を見つけます。ファイルが多すぎないように、特定の数のファイルに到達したことを検出するスレッドがあります(hbase.hstore.compaction .max)。次に、圧縮と呼ばれるプロセスでそれらをマージしようとします。このプロセスでは、基本的に、ファイルのマージの結果として新しい大きなファイルが作成されます。

    HBaseには2種類の圧縮があります。1つは2つ以上の小さなファイルを1つにマージする「マイナー圧縮」と呼ばれ、もう1つはリージョン内のすべてのファイルを取得してマージしてクリーンアップを実行する「メジャー圧縮」と呼ばれます。主要な圧縮では、削除されたキー/値が削除され、この新しいファイルにはトゥームストーンマーカーが含まれず、重複するすべてのキー/値(値の置換操作)が削除されます。

    バージョン0.20まで、HBaseはMapFile形式を使用してデータを保存していましたが、0.20では新しいHBase固有のMapFileが導入されました(HBASE-61)。

    HFile v1

    HBase 0.20では、MapFileはHFile(HBase用の特定のマップファイル実装)に置き換えられています。考え方はMapFileと非常に似ていますが、単なるキー/値ファイルよりも多くの機能が追加されています。メタデータやインデックスのサポートなどの機能が同じファイルに保持されるようになりました。

    データブロックには、実際のキー/値がMapFileとして含まれています。 「ブロッククローズ操作」ごとに、最初のキーがインデックスに追加され、インデックスはHFilecloseに書き込まれます。

    HFile形式では、MetaとFileInfoの2つの「メタデータ」ブロックタイプも追加されます。これらの2つのキー/値ブロックは、ファイルを閉じるときに書き込まれます。

    Metaブロックは、キーを文字列として使用して大量のデータを保持するように設計されていますが、FileInfoは、キーと値が両方ともバイト配列である小さな情報に適した単純なマップです。 RegionserverのStoreFileは、メタブロックを使用してブルームフィルターを保存し、最大シーケンスIDのFileInfo、メジャー圧縮キー、およびタイムレンジ情報を保存します。この情報は、キーが存在する可能性がない場合(ブルームフィルター)、ファイルが古すぎる場合(Max SequenceId)、またはファイルが新しすぎて(Timerange)、探しているものを含めることができない場合に、ファイルの読み取りを回避するのに役立ちます。のために。

    HFile v2

    HBase 0.92では、大量のデータが保存されている場合のパフォーマンスを向上させるために、HFile形式が少し変更されました(HBASE-3857)。 HFile v1の主な問題の1つは、すべてのモノリシックインデックスと大きなブルームフィルターをメモリにロードする必要があることです。この問題を解決するために、v2ではマルチレベルインデックスとブロックレベルブルームフィルターが導入されます。その結果、HFile v2の機能により、速度、メモリ、キャッシュの使用量が改善されました。

    このv2の主な機能は「インラインブロック」です。このアイデアは、ファイル全体のインデックス全体とブルームフィルターをメモリに保持するのではなく、ブロックごとにインデックスとブルームフィルターを分割することです。このようにして、必要なものだけをRAMに保持できます。

    インデックスがブロックレベルに移動されるため、マルチレベルインデックスが作成されます。つまり、各ブロックには独自のインデックス(leaf-index)があります。各ブロックの最後のキーは、マルチレベルインデックスをb+treeのようにする中間/インデックスを作成するために保持されます。

    ブロックヘッダーにいくつかの情報が含まれるようになりました。「BlockMagic」フィールドは、ブロック「Data」、Leaf-Index、Bloom、Metadata、Root-Indexなどのコンテンツを説明する「BlockType」フィールドに置き換えられました。フィールド(圧縮/非圧縮サイズおよびオフセットprevブロック)が追加され、高速の後方および前方シークが可能になりました。

    データブロックエンコーディング

    キーはソートされており、通常は非常に類似しているため、汎用アルゴリズムよりも優れた圧縮を設計することができます。

    HBASE-4218はこの問題を解決しようとしましたが、HBase 0.94では、プレフィックスと差分エンコーディングの2つの異なるアルゴリズムから選択できます。

    プレフィックスエンコーディングの主なアイデアは、行が並べ替えられ、最初は通常同じであるため、共通のプレフィックスを1回だけ保存することです。

    Diff Encodingは、この概念をさらに推し進めます。キーをバイトの不透明なシーケンスと見なす代わりに、Diff Encoderは、各部分をより適切に圧縮するために、各キーフィールドを分割します。これは、列ファミリーが1回保存されるということです。キーの長さ、値の長さ、およびタイプが前の行と同じである場合、フィールドは省略されます。また、圧縮率を高めるために、タイムスタンプは前のタイムスタンプとの差分として保存されます。

    書き込みとスキャンは遅くなりますが、より多くのデータがキャッシュされるため、この機能はデフォルトでオフになっていることに注意してください。この機能を有効にするには、DATA_BLOCK_ENCODING =PREFIX|を設定します。 DIFF |テーブル情報のFAST_DIFF。

    HFile v3

    HBASE-5313には、圧縮を改善するためにHFileレイアウトを再構築する提案が含まれています。

    • ブロックの最初にすべてのキーをまとめ、ブロックの最後にすべての値をまとめます。このようにして、2つの異なるアルゴリズムを使用してキーと値を圧縮できます。
    • 最初の値のXORを使用してタイムスタンプを圧縮し、longの代わりにVIntを使用します。

    また、列形式または列エンコードは調査中です。DougCuttingによる列ファイル形式についてはAVRO-806を参照してください。

    ご存知のように、進化の傾向は、ファイルに何が含まれているのかをよりよく認識し、ディスクからの書き込み/読み取りのデータを減らすことで、より優れた圧縮またはより優れた位置認識を実現することです。 I / Oが少ないほど、速度が速くなります。

    [1] https://clouderatemp.wpengine.com/blog/2011/01/hadoop-io-sequence-map-set-array-bloommap-files/
    [2] https://clouderatemp.wpengine。 com / blog / 2012/06 / hbase-write-path /


    1. ファイルまたはアセンブリを読み込めませんでしたSystem.Runtime.CompilerServices.Unsafe

    2. Mongoグループとプッシュ:すべてのフィールドをプッシュ

    3. Redis:ソートされたセットのスコアの合計

    4. ClusterControlを使用したデータベースユーザー管理