HBase 1.2で導入されたSimpleRegionNormalizerを試してみる

RegionNormalizer

Distributed computing (Apache Hadoop, Spark, …) Advent Calendar 2016」 の@d1ce_氏による「HBase 1.2で導入されたSimpleRegionNormalizerについて」で紹介されていたRegionNormalizerの機能を試してみました。
HBaseはテーブルを「リージョン」という範囲に分けて管理します。例えば以下の図では4つのリージョンに分かれていますが、図Aはほぼ均等になっているのに対し、図Bは不均等になっています。

normalizerこのように不均衡が生じると、リージョンが割り当てられているサーバーに負荷が集中してしまったり、特定リージョンへの書き込みが集中することで、リージョンサイズ(デフォルト10GB)を超えてしまい、分割が頻繁に発生する(split storm)など、パフォーマンスの問題の原因にもなります。
リージョンの分割やマージは手動で行うことも可能ですが、RegionNormalizerは定期的に自動で調整を行ってくれるという素敵な機能です。仕組みは詳細は上記のd1ce_氏の記事をご覧ください。

環境

  • CDH 5.9 (+Cloudera Manager 5.9)

テスト

まず、事前スプリットしたテーブルを作成します。
[code]
hbase(main):010:0> create ‘ntable’, ‘cf’, {SPLITS => [‘A’, ‘M’, ‘Z’]}
0 row(s) in 1.2270 seconds
[/code]
これは、下記のように4つの空のリージョンを作成しています。
before_normalization
この図で見ると

  1. Start ” -> End ‘A’
  2. Start ‘A’ -> End ‘M’
  3. Start ‘M’ -> End ‘Z’
  4. Start ‘Z’ -> End (それ以降)

の4リージョンになっていますね。
各リージョンに以下のようなスクリプトで適当なデータを書き込みます。その際、意図的に偏らせています。今回は最初のリージョンに多くのデータを書き込みました。
[code]
for i in ‘a’..’z’ do
for j in ‘a’..’z’ do
for k in ‘a’..’z’ do
put ‘ntable’, "A-#{i}#{j}#{k}", "cf:#{i}", "#{i}#{j}#{k}" end end end
[/code]
書き終わったらフラッシュします。
[code]
hbase(main):028:0> flush ‘ntable’
0 row(s) in 0.3790 seconds
[/code]
各リージョンの行数を直感的に見る術はないのですが、RegionServerのUIでは以下のように見えます。
before_normalization_storefile最初のリージョンのStoreFileが幾分大きいように見えますね。
あるいは、すべての行数であれば、MapReduceを使った RowCounter を利用できます。
[code]
$ HADOOP_CLASSPATH=`hbase classpath` hadoop jar /opt/cloudera/parcels/CDH/lib/hbase/hbase-server.jar rowcounter ntable
(略) org.apache.hadoop.hbase.mapreduce.RowCounter$RowCounterMapper$Counters
ROWS=509704
File Input Format Counters
Bytes Read=0
File Output Format Counters
Bytes Written=0
$
[/code]
Cloudera ManagerのHBaseには「テーブルの統計」を表示する機能があります。これを見るとリージョンサイズの偏りがあることが可視化されていますね。
hbase_chart_before時系列で表示されいるので、テーブルにデータを書き込んでいるところから8:30頃に偏りが生じていることが見て取れます。
さぁ、ノーマライズの時間です!
それではNormalizerを有効にします。テーブルを変更するため、一度テーブルを無効化してから設定しましょう。
[code]
hbase(main):038:0> desc ‘ntable’
Table ntable is ENABLED
ntable
COLUMN FAMILIES DESCRIPTION
{NAME => ‘cf’, DATA_BLOCK_ENCODING => ‘NONE’, BLOOMFILTER => ‘ROW’, REPLICATION_
SCOPE => ‘0’, VERSIONS => ‘1’, COMPRESSION => ‘NONE’, MIN_VERSIONS => ‘0’, TTL =
>; ‘FOREVER’, KEEP_DELETED_CELLS => ‘FALSE’, BLOCKSIZE => ‘65536’, IN_MEMORY => ‘
false’, BLOCKCACHE => ‘true’}
1 row(s) in 0.0300 seconds
hbase(main):039:0> disable ‘ntable’
0 row(s) in 2.2820 seconds
hbase(main):040:0> alter ‘ntable’, ‘NORMALIZATION_ENABLED’ => true
Updating all regions with the new schema…
4/4 regions updated.
Done.
0 row(s) in 1.9720 seconds
hbase(main):041:0> normalizer_switch true
true
0 row(s) in 0.0190 seconds
hbase(main):042:0> normalizer_enabled
true
0 row(s) in 0.0140 seconds
hbase(main):043:0> enable ‘ntable’
0 row(s) in 1.2530 seconds
hbase(main):044:0>
[/code]

ログを確認する

normalizerはデフォルト5分間隔で実行されます。Cloudera ManagerでHMasterのログを見てみましょう。Cloudera Managerのログ検索で、HMasterからNormalizerという単語で検索をかけてみます。
cm_logすると、メッセージでNormalizerが2つのプランを表示していることがわかりました。

  1. Executing splitting normalization plan
  2. Executing merging normalization plan

実行が終わったら、再度RegionServerのUIを見てみましょう。
after_normalization先ほどとはリージョンのStart Key, End Keyが変わっていることがわかります。

No.Normalize前
開始キー
Normalize前
終了キー
Normalize後
開始キー
Normalize後
終了キー
1A1-mnbd
2AM1-mnbdA
3MZAZ
4ZZ

今回RegionNormalizerは、最初のリージョンを分割し、次の2つのリージョンをマージしたようです。
Cloudera Managerでも確認しておきましょう。
hbase_chart_after時間範囲を拡大し、Normalizerによって、リージョンサイズの平均、最大、最小が平準化されたことがわかります。リージョンサイズのチャートを拡大してみると
region_size8:34頃にNormalizerが実行されたのが一目瞭然でわかりますね。先ほどのCloudera Managerで確認したログの時間とも一致しています。(当然ですが、、)

まとめ

このように、RegionNormalizerは自動でリージョンの平準化を行ってくれていることが確認できました。サイズを見て自動で行ってくれる素晴らしい機能ですが、高負荷の時に分割やマージが実行されるのも悩ましいので、負荷の低い時間帯に有効にするなどの運用が必要でしょう。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です