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 をオーバーライドして実装可能である。

Data Versioning

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件が出ることがわかる。