HBase データバージョニング(Data Versioning)
データバージョニング(Data Versioning)
HBase の特別な機能の1つとして、各セル(cell)の特定 column 値に複数のバージョンを保存できる。
各バージョンには timestamp を使用して実装されており、降順にソートされる。long integer 型として、millisecond に換算した UnixTime を使用する。
HBase は基本的にデータバージョン管理を行う。データが同じ Row key で保存されると、最新データが timestamp でバージョニングされ、降順に保存されるため、ストレージファイルから読み取るときにもっとも新しい値を先に見つける。
Timestamp は明示的に入力することも可能だが、デフォルトで HBase は各 cell の変更を3個まで保持し、基本的に scan で照会すると降順であるため最新データが照会される。
また、以下のように保存されているすべての version のデータを照会することも可能である。
get 't1', 'rowkey1', {COLUMN => 'cf1', TIMESTAMP => ts1}
timestamp 範囲を設定して、その時点の値を見ることも可能である。
get 't1', 'rowkey1', {TIMERANGE => [start_timestamp, end_timestamp]}
バージョニングは既存では自動で指定されるが、手動で指定することもできる。
- 自動バージョニング
- クラスター内サーバー時間が同一でない場合、バージョン差が発生する可能性がある。
- Put メソッド実行時に timestamp を設定できるが、一般的にはサーバー内の自動バージョニングを推奨する。
- 基本的に最近3個のバージョンを管理するが、Major Compaction 機能が長い周期を持つため、まだ削除されていない過去バージョンが存在することがある。
- 手動バージョニング
- timestamp をオーバーライドして実装可能である。

HBase VERSIONS=1 の場合でも削除すると列の以前のバージョンが表示される?
前でバージョンは基本的に最近3個のバージョンを管理するが、Major Compaction 機能が長い周期を持つため、まだ削除されていない過去バージョンが存在することがあると述べた。
これに関連して発生する問題について紹介する。
VERSIONS 適用
以下のように ColumnFamily に VERSIONS を適用する。
create 't1', {NAME => 'f1', VERSIONS => 2}
hbase(main):001:0> create 't1', {NAME => 'f1', VERSIONS => 2}
Created table t1
Took 5.9091 seconds
=> Hbase::Table - t1
次にデータを順番に登録する。
put 't1', '101', 'f1:name1', 'test1'
put 't1', '101', 'f1:name1', 'test2'
put 't1', '101', 'f1:name1', 'test2'
put 't1', '101', 'f1:name1', 'test4'
hbase(main):002:0> put 't1', '101', 'f1:name1', 'test1'
Took 0.7153 seconds
hbase(main):003:0> put 't1', '101', 'f1:name1', 'test2'
Took 0.0318 seconds
hbase(main):004:0> put 't1', '101', 'f1:name1', 'test3'
Took 0.0418 seconds
hbase(main):005:0> put 't1', '101', 'f1:name1', 'test4'
Took 0.0255 seconds
そして delete コマンドで1つずつ順番に削除しながら確認してみる。
delete 't1', '101', 'f1:name1'
hbase(main):013:0> scan 't1'
ROW COLUMN+CELL
101 column=f1:name1, timestamp=1687426826665, value=test4
1 row(s)
Took 0.3049 seconds
hbase(main):014:0> delete 't1', '101', 'f1:name1'
Took 0.0160 seconds
hbase(main):015:0> scan 't1'
ROW COLUMN+CELL
101 column=f1:name1, timestamp=1687426822568, value=test3
1 row(s)
Took 0.1760 seconds
hbase(main):016:0> delete 't1', '101', 'f1:name1'
Took 0.0605 seconds
hbase(main):017:0> scan 't1'
ROW COLUMN+CELL
101 column=f1:name1, timestamp=1687426817569, value=test2
1 row(s)
Took 0.0710 seconds
hbase(main):018:0> delete 't1', '101', 'f1:name1'
Took 0.0337 seconds
hbase(main):019:0> scan 't1'
ROW COLUMN+CELL
101 column=f1:name1, timestamp=1687426813634, value=test1
1 row(s)
Took 0.0265 seconds
hbase(main):020:0>
すると、その直前に登録したデータが順番に照会されることがわかる。
VERSIONS に関する疑問
ここでの疑問は、明らかに VERSIONS は1個だけ保存されると言われているのに、VERSIONS => 2 と指定してもそれ以上のバージョンの列が保持されているように見える点である。一見するとバグではないかと疑われる。
検索してみると、以下のように同じ疑問を持った人を見つけることができた。
Delete reveals older version of a column even when VERSIONS=1
上記質問には以下のような回答がある。
圧縮が行われるまでは以前のバージョンが実際には消えないという。圧縮は major compaction 設定を変更していない場合、またはリージョンが分割されるたびに、1日に1回実行されるべきだという。
これは Major Compaction がまだ行われていないために発生する問題である。
VERSIONS 適用の確認方法
では、VERSIONS はどう確認できるだろうか。方法は get コマンドを利用して VERSIONS => 4 のように詳細照会してみれば確認できる。
get 't1', '101', {COLUMN=>'f1:name1',VERSIONS => 4 }
hbase(main):005:0> get 't1', '101', {COLUMN=>'f1:name1', VERSIONS => 4 }
COLUMN CELL
f1:name1 timestamp=1687427184339, value=test4
f1:name1 timestamp=1687427181122, value=test2
1 row(s)
Took 0.5028 seconds
hbase(main):006:0>
すると上記のように、テーブル作成時に指定した VERSIONS => 2 どおり2件が出ることがわかる。