HBaseの全体像
前回も軽く触れましたが、HBaseはマスタ型でHMasterとHRegionServerという2種類のプロセスがいます。
- HMaster:Regionの管理やHRegionServerへの割り当てなどを行います
- HRegionServer:実際にクライアントとデータのやり取りを行います
また、Zookeeperというコーディネーションサービスを用いており、死活監視やこの後説明する-ROOT-のRegionの情報などを保持しています。
HBaseは、-ROOT-と.META.という2つの特別なカタログTableを持っています。これは、前述したTableと同じ構造になります。
- -ROOT-には、.META.のRegionの情報(RegionのRowKeyの範囲や、どのHRegionServerに割り当てられているかなど)が入っています
- .META.には、その他のすべてのTableのRegionの情報が入っています
あるデータにアクセスをしたい場合は、下記のような流れになります。
- クライアントはまずZookeeperにアクセスをし、-ROOT-が割り当てられているHRegionServerの情報を取得します
- そして、-ROOT-のRegionが割り当てられているHRegionServerから、.META.が割り当てられているHRegionServerの情報を取得します
- 最後に、.META.の内容からアクセスしたいデータのRegionが割り当てられているHRegionServerの情報を取得し、実際にデータにアクセスします
このように、初めてデータにアクセスする際、クライアントは複数回のホップを経る必要がありますが、2回目以降はこれらの情報をキャッシュしているため1ホップでアクセスすることができます。また、Regionの割り当てが変更された場合は、クライアントは1ホップでアクセスしようとしますが、実際には該当Regionがないので、再度.META.にアクセスし直します。
下のイメージ図は、クライアントがTable名"TBL"のRegion2にアクセスしたい場合の手順です。
HBaseの書き込みフロー
次に、HBaseの書き込みフローについて説明します。前回でも説明した通り、HBaseには書き込みが速いという特徴があります。
HRegionServerは、クライアントからputのリクエストがくると、メモリ上にあるMemStoreにデータを書き込みます。当然メモリ上にあるデータは、プロセスがダウンした際に失われてしまいます。
そこでHRegionServerはデータをMemStoreに書き込む前に、WAL(Write Ahead Log)をファイルシステムに書き込みます。このようにすることで、データの安全性を保証しています。WALの書き込みは、シーケンシャルな書き込みになるので高速です。
MemStoreはRegion数×ColumnFamily数だけ存在し、WALはHRegionServerごとに1つ存在します。
下のイメージ図では、RowKeyが"row3"でColumnFamilyが"ColumnFamily1"、Columnが"Column1"、Timestampが"400"、Valueが"fff"のデータを追加しています。
RowKey+ColumnFamily+Column+Timestampでソートされた状態で挿入されます。
また前回、HBaseは強い一貫性を持ち、同じRowに関する複数の操作はアトミックに行われるという説明をしました。
HBaseでは、データをRowKeyの範囲でRegionという単位に分割しており、各Regionは単一のHRegionServerに割り当てられます。このことにより、比較的シンプルに強い一貫性の実現や、同じRowに関する複数の操作はアトミックに行うことができます。また、同様の理由からインクリメントやCAS操作も可能です。
deleteについては、実際にデータを削除することはせずに、削除マーカーを書き込むということをします。実際にデータが消えることはないので、読み込み時に削除マーカーが存在していたらデータを無視するということでdeleteを実現しています。実際に削除が行われるのは、この後説明するメジャーCompaction時になります。
Flushについて
メモリに乗せることのできるデータ量は、ディスクに比べて多くありません。当然、書き込まれたデータをすべてメモリに置いておくことはできないので、HBaseはMemStoreのサイズがある一定以上を超えたら、MemStore上のデータをディスクに書き込むということをします。これを、Flushと呼びます。
Flushが起きたMemStoreのデータはHFileという1つのファイルに書き込まれます。HFileは、この後に説明するCompactionが起きない限り、変更されることはありません。
MemStoreのサイズがある一定以上を超えるたびにFlushされるので、HFileはだんだん増えてくことになります。
MemStoreはRegionとColumnFamilyごとに1つ存在しますが、HFileはRegionとColumnFamilyごとに複数存在することになります。
別のColumnFamilyに所属するColumnは別のHFileに書き込まれます。これにより、同時にアクセスされるColumnを同一のColumnFamilyに所属させると、HFileへのI/Oの切り分けが可能になります。
これが、列指向データフォーマットのメリットの一つです。




