Pivotal Knowledge Base

フォローする

HBaseの基礎

マスタサーバとリージョンサーバ、リージョンの理解

リージョンはテーブルのデータの補集合であり、本質的には、一緒に格納された行のソートされた連続領域である。リージョンは、テーブルの可用性と分散の基本的な要素である。

HRegionServer はリージョンサーバの実装である。これは、リージョンのサービス提供や管理を担当する。分散型クラスタでは、リージョンサーバはデータノード上で稼働する。各リージョンサーバは、リージョン集合を提供する責任があり、一つのリージョン(すなわち行領域)はただ一つのリージョンサーバによって提供される。

HMaster はマスタサーバの実装である。マスタサーバは、クラスタ内のすべてのリージョンサーバインスタンスを監視する責任があり、すべてのメタデータ変更時のインターフェースである。分散型クラスタでは、HMasterは一般的にNameNodeは上で稼働する。単一クラスタ上で複数のマスタを持つことができるが、その際はすべてのマスタがクラスタの実行に競合することになるので、いずれかがアクティブなマスタとなる。アクティブなマスタがZooKeeper管理下で期限内の応答がない(またはマスタがシャットダウンした)場合、残りのマスタのいずれかがアクティブとなりその役割を引き継ぐ。

リージョン分割

最初は、1つのテーブルに1つだけリージョンが存在する。より多くの行を追加した結果リージョンが大きくなりすぎた場合、リージョンは中央のキーで2分割され、おおよそ半分ずつのリージョンになる。

 

 

  • 事前分割

テーブル作成時に分割ポイントを提供することで多くのリージョンを持つテーブルを作成する。推奨は事前分割だが注意点がある。不適切に分割点を選択すると、負荷分散が不均一となり、クラスタのパフォーマンスが低下する恐れがある。

  • 自動分割

デフォルトの分割ポリシー。リージョン内のデータストアの一つにおいて、データサイズの合計が、“hbase.hregion.max.filesize”(デフォルトは 10GB)よりも大きくなるとリージョンを自動分割する。

  • 手動分割

CLIから、不均一に負荷分散されたリージョンを手動分割する。

***********************************************************************************

例:

hbase(main):024:0> split 'b07d0034cbe72cb040ae9cf66300a10c',    'b'
             0 row(s) in 0.1620 seconds

***********************************************************************************

リージョンの割当と負荷分散

起動時のリージョン割当

HBase起動時に、リージョンは以下のように割り当てられる(簡易版):

  1. マスタは起動時にAssignmentManager を立ち上げる
  2. AssignmentManager はMETA内にある既存リージョンの割当状況を確認する
  3. リージョンの割当が有効の場合(すなわち、リージョンサーバがオンラインの場合)、その割当は保持される。
  4. 割当が無効である場合には、LoadBalancerFactoryがリージョンを割り当てるために呼び出される。DefaultLoadBalancerは、ランダムでリージョンサーバーにリージョンを割り当てる。
  5. META はリージョンサーバの割当に応じて(必要な場合に)更新され、リージョンサーバはリージョンサーバによるリージョン開始に応じたコード(リージョンサーバプロセスの開始時刻)を実行する。

フェールオーバ時のリージョン割当

  1. リージョンサーバが停止すると、すぐにリージョンが利用出来なくなる。
  2. マスタはリージョンサーバの停止を検知する。
  3. リージョンの割当は無効と見なされ、起動時と同様に再度リージョンを割り当てる。

ロードバランシング時のリージョンの割当

ロードバランサは、移動中のリージョンがない場合に定期的に実行され、クラスタの負荷を平準化するために適宜移動を実施する。バランサは、クラスタ上のリージョンを再配置するため、マスタ上で実行される。実行間隔は、hbase.balancer.periodで設定され、デフォルト値は300000 (5 分)である。

HBaseデータモデル

HBaseのテーブルは、行と列で構成されている。HBaseの全ての列は特定のカラムファミリに属する。表のセル(行と列の交点座標)はバージョン管理されている。セルの内容は連続したバイト列である。

HBaseのテーブルにおける行は、行キーでソートされている。ソートは、バイト順で行われる。すべてのテーブルアクセスは、テーブルの行キー(いわゆる、主キー)を介して行われる。

カラムファミリ

列名は、そのカラムファミリ名からなる接頭辞と修飾子で構成されている。たとえば、contents:htmlという列は、カラムファミリcontentsに属する。なお、コロン記号(:)はカラムファミリ名と修飾子との区切り文字である。

HBase テーブル例を示す(webtable の例を引用) 

行キー

タイムスタンプ

カラムファミリ contents

カラムファミリ anchor

"com.cnn.www"

t9

 

anchor:cnnsi.com="CNN"

"com.cnn.www"

t8

 

anchor:my.look.ca="CNN.com"

"com.cnn.www"

t6

contents:html="<html>..."

 

"com.cnn.www"

t5

contents:html="<html>..."

 

"com.cnn.www"

t3

contents:html="<html>..."

 

 

タイムスタンプ t8 の contents:html 列値への要求は値を返さないであろう。同様に、タイムスタンプ t9 の anchor:my.look.ca 列値への要求は値を返さないであろう。しかしながら、タイムスタンプを特に指定しない場合は、特定の列の最新の値が返され、なおかつ当該テーブルで最初に見つかった値となる。なぜなら、タイムスタンプは降順で格納されているためである。よって、タイムスタンプを明示指定しない com.cnn.www 行の全ての列値への要求は、タイムスタンプ t6 からは contents:html 、タイムスタンプ t9 からは anchor:cnnsi.com 、タイムスタンプ t8 からは anchor:my.look.ca のように値を返すであろう。

すべてのカラムファミリのメンバは、物理的に同一ファイルシステム上に格納されている。チューニングおよびストレージ仕様決定はカラムファミリレベルで行われているため、すべてのカラムファミリのメンバは、全体的に同一のアクセスパターンおよびサイズ特性を持つことが推奨される。

セル

HBase においては、タプル(行、列、バージョン)により、セルが特定される。セルの内容は連続したバイト列である。

バージョン

行や列が全く同じ値を持つセルであるが、セルの座標においてバージョンの次元のみ変えることで無制限数のセルを持つことが可能である。

バージョンは長精度整数で表される。典型的に、この長精度整数値には、 java.util.Date.getTime() もしくは System.currentTimeMillis() によって返されるような時間インスタンスが含まれる。すなわち、"現在時刻と協定世界時における 1970 年 1 月 1 日深夜との、ミリ秒で表される差分" である。

基本的なHBaseの操作

get: 指定された行の属性を返す。明示的にバージョンが指定されていない場合は、バージョンの値が最大のセルを返す。

put: キーが新規の場合はテーブルに新しい行を追加し、キーがすでに存在している場合は既存の行を更新する。 putを実行すると常に、ある時点でのタイムスタンプで新しいバージョンのセルが作成される。デフォルトでは、システムはサーバのcurrentTimeMillis値を使用するが、列単位のレベルでのバージョン(=長精度整数)を自身で指定することができる。これは、過去や未来の時間を割り当てたり、時間以外を表す目的で長精度整数値を使用できることを意味する。

scan: 指定された属性に対する、複数行への反復処理。バージョンを指定したGETと同じような振る舞いである。

delete: テーブルから行を削除する操作で、3種類存在する。

  • Delete: 特定バージョンの列に対して
  • Delete column: 全バージョンの列に対して
  • Delete family: 特定のカラムファミリの全ての列に対して

HBaseは所定の位置でデータを変更せず、削除の際はtombstoneと呼ばれる新たなマーカーを生成することにより実現している。このtombstoneは、削除対象の値と一緒に主要なコンパクション処理でクリーンアップされる。

カタログテーブル

カタログテーブルは、ユーザテーブル情報を維持するためにHBaseによって使用される。2つのカタログテーブル(-ROOT-と.META.)が存在する。

-ROOT-

-ROOT-は.META.テーブルの位置をトラッキングする。-ROOT-テーブルの構成を以下に示す。

キー:

  •   .META.リージョンキー(.META.,,1)

値:

  • info:regioninfo(.META.のシリアライズされたHRegionInfoインスタンス)
  • info:server(.META.を保持するリージョンサーバの server.port 値)
  • info:serverstartcode(.META.を持つリージョンサーバプロセスの起動時間)

.META.

.META.テーブルはシステムの内の全てのリージョンリストを保持する。.META.テーブルの構成を以下に示す。 

キー:

  • "[テーブル],[開始リージョンキー],[リージョン ID]"というフォーマットからなるリージョンキー

値:

  • info:regioninfo(シリアライズされた当該リージョンの HRegioninfo インスタンス)
  • info:server(当該リージョンを含むRegionSeverのserver:port値)
  • info:serverstartcode(当該リージョンを含むRegionServerプロセスの起動時間)

メモ: HBase起動時、HMasterは各HRegionServerにリージョンを割り当てる役割を担う。これにもまた、"特殊な" -ROOT- テーブルと.META.テーブルを含まれる。

Write Ahead Log(WAL)と HLog

WAL

WALは、障害発生時に必要となるライフラインといえる。 MySQLのBINログと同様に、データへのすべての変更が記録される。これはプライマリストレージに何か発生した場合に重要となる。サーバーがクラッシュした場合、ちょうどクラッシュする直前のあるべき状態を回復するために、当該ログの内容を効果的に再実行することが可能である。また、WALに対するレコード書き込みが失敗した場合、全体の操作が失敗と見なさなければならない。
WALは、標準的なHadoopシーケンスファイルであり、HLogKeyを保持している。これらのキーは、連続した数字と実際のデータが含まれ、サーバがクラッシュした後、未永続化データの書き込みを再実行するために使用される。
各リージョンサーバは、最初に、更新(Put、Delete)内容を write-ahead Log(WAL)に書き込み、次にStoreに対応するMemstoreへ更新を行う。これは、HBaseは、Durable Write 機構を持つことを保証する。WAL がないと、各MemStoreがフラッシュされ、新規StoreFileにデータが書き込まれる前にリージョンサーバー障害が発生した場合、当該データを失う可能性がある。HLogは、HBaseのWALの実装であり、リージョンサーバごとに1つのHLogインスタンスが存在する。

(MemstoreやStore、データがHBaseでどのように保存されるかについては下記で述べる)

HLog

WALを実装するクラスはHLogと呼ばれている。HLogクラスの仕様はここで確認できる。

HRegionがインスタンス化されると、単一のHLogはHRegionのコンストラクタにパラメータとして渡される。

HLogは重要な特徴がある。

  • HLogは append() を持っていて、内部で最終的に doWrite() を呼び出す。
  • HLogは変更箇所をトラッキングし続ける。
  • HLogは、クラッシュしたHRegionServerが残したログを回復、分割する機能を持つ。

HBase と Zookeeper

概要

ZooKeeperクラスタはHBase全体のコーディネーションサービスとして動作し、マスタ選択の操作、rootリージョンサーバのルックアップ、ノード登録などを行う。リージョンサーバやリージョンマスタの検知はZookeeper経由で行う。

全ての対象ノードとクライアントは、稼働しているZooKeeperアンサンブルにアクセスできるようにする必要がある。デフォルトでは、Apache HBaseはZooKeeper"クラスタ"自体も管理する。その場合、HBaseは起動/停止プロセスの一環でZooKeeperアンサンブル自体の起動/停止を行うことになる。一方、ZooKeeperアンサンブルをHBaseとは独立して管理することも可能で、その場合は、HBaseが使用すべきクラスタを指定することになる。ZooKeeperのHBaseのZooKeeper管理動作を切り替えるためには、conf/hbase-env.sh 内の HBASE_MANAGES_ZK 変数を使用する。この変数はデフォルトでtrueであり、HBaseに対しての起動/停止プロセスの一環でZooKeeperアンサンブルサーバの起動/停止を行うようになっている。

HBaseがZooKeeprアンサンブルを管理するとき、ZooKeeperの設定をネイティブ設定ファイルであるzoo.cfgを使用して行うことも可能だが、より簡単な選択肢として、ZooKeeperのオプションをconf/hbase-site.xml 内で直接指定するこも可能である。ZooKeeperの設定オプションは、ZooKeeperオプション名にプリフィックスとしてhbase.zookeeper.propertyを付与することによって、HBaseのhbase-site.xml XML設定ファイルのプロパティとして設定することができる。例えば、ZooKeeperのclientPortプロパティは、hbase.zookeeper.property.clientPortプロパティと変更することになる。

ZK上のHBaseディレクトリの構成


 

  • マスタ(Master)
    • 複数のマスタがあれば、マスタ選挙が強制実行される。
  • Rootリージョンサーバ(Root Region Server)
    • このznodeは、HBaseにおける全テーブルのrootを有するサーバーの場所情報を保持している。
  • rs
    • HBaseリージョンサーバごとのznodeがあるディレクトリ。
    • リージョンサーバは、オンラインになる際、Zookeeperに自身の情報を登録する。
  • リージョンサーバ障害時(短命なznodeやZookeeper経由で検知)、マスタがリージョン毎に、リージョン分割を実施する。

 

HBase におけるデータ格納

全体像




HBaseは基本的に2種類のファイルを扱う。1つはwrite-ahead logで、もう1つは実際のデータストレージに使用される。これらのファイルは基本的にHRegionServerが取り扱う。しかし特定の場合で、HMasterが低レベルなファイル操作を行うことがある。

データフロー

  1. 新規クライアントは始めに、特定の行キーを見つけるため、Zookeeperクォーラム(ZooKeeperノードの分割されたクラスタ)に接続を行う。この接続処理は、ZooKeeperから -ROOT- リージョンを保持するサーバーの名前(つまり、ホスト名)を取得することによって実現する。
  2. その情報を利用して、クライアントは、.META.テーブルを持つサーバ情報を取得するため、-ROOT- のサーバを照会することができる。これらの詳細な情報は共にキャッシュされ一度だけルックアップされる。
  3. クライアントは .META. のサーバーを照会し、クライアントがルックアップする行を持つサーバを取得することができる。
  4. 一度、クライアントがどこに(すなわち、どのリージョンに)対象の行があるか特定すると、クライアントはその情報をキャッシュし、直接そのリージョンを持つHRegionServerと通信を行う。このように、クライアントは、徐々に、.META.のサーバーを再度参照する必要なくどこから行を取得すべきか、かなりの割合で全体像を把握するようになる。
  5. 他方、HRegionServerがリージョンをオープンする際、対応するHRegionオブジェクトを作成する。HRegionが "オープンされる"と、あらかじめユーザにより定義されたように、全テーブルの各HColumnFamilyに対するStoreインスタンスを設定する。各Storeインスタンスは順次、1つ以上のStoreFileを保持することができる。それらはHFileと呼ばれる実ストレージファイルの軽量ラッパーである。HRegionはまた、MemStoreHLogインスタンスも保持する。
  6. データが、最初にHLogクラスによって実装された"Write-Ahead-Log"(WAL)に書き込むべきかの決定は、クライアントによってPut.writeToWAL(boolean) メソッドを使用して設定されたフラグに基づき行われる。
  7. 一度、データがWALに書き込まれると(あるいは、書き込まれない場合でも)、MemStoreにも書き込まれる。同時に、WALMemStoreに空きがあるかどうか確認する。もし空きがなければ、ディスクフラッシュの実行要求を行う。当該要求はHRegionServerにおける別スレッドにより処理され、HDFSに配備されているHFileにデータを書き込む。WALはまた、システムがこれまでにどのデータが永続化されたか把握できるよう、最後に書き込まれたデータのシーケンス番号も保存する。


 

 

 

 

コメント

Powered by Zendesk