HBase 데이터 버저닝(Data Versioning)

데이터 버저닝 (Data Versioning)

HBase의 특별한 기능 중 하나로 각 셀(cell)의 특정 column 값에 여러 버전을 저장 한다.

각 버전에 타임스탬프(timestamp)를 사용하여 구현되었으며 내림차순으로 정렬된다. long integer 타입으로 millisecond로 환산한 유닉스시간(UnixTime)을 사용한다.

HBase는 기본적으로 데이터 버전 관리를 한다. 데이터가 동일한 Row key로 저장이 되면, 가장 최신 데이터가 timestamp로 버전닝을 하여 내림차순으로 저장되므로, 저장소 파일에서 읽을 때 가장 최근 값을 먼저 찾게 된다.

Timestamp는 명시적으로 입력하는 것도 가능한데, default로 HBase는 각 cell의 변경을 3개 까지 보관하며 기본적으로 scan을 통해서 조회하게 되면 내림차순이기 때문에 가장 최신의 데이터가 조회된다.

그리고, 아래와 같이 저장되어 있는 모든 version의 데이터를 조회하는 것도 가능하다.

get 't1', 'rowkey1', {COLUMN => 'cf1', TIMESTAMP => ts1}

timestamp 범위를 설정하여m 그 시점의 값을 보는 것도 가능하다.

get 't1', 'rowkey1', {TIMERANGE => [start_timestamp, end_timestamp]}

버저닝은 기존 자동으로 지정되는데, 수동으로 지정할 수도 있다.

  • 자동 버저닝
    • 클러스터 내 서버 시간이 동일하지 않은 경우 버전 차이 발생 가능한다.
    • Put 메소드 수행 시 타임스탬프를 설정할 수 있으나 일반적으로 서버 내 자동 버저닝 권장한다.
    • 기본적으로 최근 3개 버전을 관리하지만 Major Compaction 기능이 긴 주기를 가지므로, (아직 삭제되지 않은) 과거 버전이 여전히 존재할 수 있다.
  • 수동 버저닝
    • 타임스탬프를 오버라이드하여 구현 가능하다.

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이 아직 이루어지지 않았기 때문에 발생하는 문제이다.

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건이 나오는걸 볼 수 있다.




최종 수정 : 2024-01-18