DynamoDB와 HBase 비교 분석하기
www.recopick.com

안녕하세요. RecoPick팀 김성민입니다.

오늘은 최근 RecoPick팀에서 DynamoDB를 사용하게 되면서 배웠던 사항을 QnA 형태로 정리했습니다. 참고로 그동안 제가 주로 HBase를 사용해왔기 때문에, 되도록 DynamoDB와 HBase를 비교하면서 설명해 보도록 하겠습니다.

1. HBase와 DynamoDB의 개념적인 차이?

  HBase와 DynamoDB의 개념적인 차이를 한마디로 말하자면, SortedMap(a.k.a TreeMap)과 HashMap의 차이점과 같습니다. java TreeMap은 element가 정렬되어서 저장되어 있으나, HashMap의 경우, 저장된 element의 정렬 순서를 보장하지 않습니다. 마찬가지로 HBase의 경우, 저장되는 데이터가 모두 alpha numeric 순서 정렬되어 있으나, DynamoDB는 저장되는 데이터의 정렬 순서를 보장하지 않습니다. 


2. HBase와 DynamoDB의 구조적인 차이?

  HBase는 Master-Slave 구조지만, DynamoDB는 Peer-To-Peer 구조로 되어 있습니다. 아래그림 처럼, HBase는 논리적으로 B+Tree 구조로 데이터를  분산해서 저장하지만, DynamoDB는 consistency hash 방식을 사용해서 저장합니다.


그림 1. Table location hierarchy



그림 2. Partitioning and replication of keys in Dynamo ring.


3. Eventually Consistent vs Strongly Consistent?

  DynamoDB의 경우,  eventually  consistent reading과 strongly consistent reading을 모두 지원하지만, Scan 연산의 경우는 eventually consistent reading만 지원합니다. (참고로, strongly consistent reading은 항상 최종 변경 내용을 반환해 주지만, eventually consistent reading은 최종 변경 내용을 항상 반환해 줄 수는 없다는 뜻입니다.)


4. Range query를 수행할 수 있는지?

  앞서 HBase와 DynamoDB의 개념상 차이에서 설명한 것처럼, DynamoDB는 개념적으로 정렬 순서를 보장하지 않는 HashMap이기 때문에, DB layer에서 range query를 지원하지 않습니다. 그럼에도 불구하고, DynamoDB에서 range query를 사용해야 한다면, 아래와 같은 방법을 고려 해 볼 수 있습니다.

  먼저 데이터 접근 패턴(access pattern)을 분석해서, DynamoDB의 키를 계층 구조로 설계하고, 동일한 키에 대해서 range query를 수행할 수 있도록 스키마를 설계해야 합니다.

  예를 들어, 1~100 사이 값을 unique id로 갖는 데이터를 저장할 때, 이 값을 그대로 key로 사용하면, DynamoDB에서는 "13~25의 값을 꺼내"와 같은 range query는 수행할 수 없습니다. 이를 우회하기 위해, 1~100 사이의 unique id를 10단위로 해서 아래와 같이 그룹핑을 한 후,



Group Id를 Hash Key로 하고, Unique Id를 Range Key로 설정해서 저장합니다. 

만약 id가 13~25 사이의 데이터를 가져오는 range query를 수행하고자 한다면, 먼저 해당 Unique Id들이 포함되는 Group Id들(이 경우에는 11, 21)를 찾습니다. 그리고 Group Id 11을 hash key로 갖는 데이터 중에서 unique id가 13~20 사이에 있는 데이터를 가져오는 query를 수행 합니다. 마찬가지로 Group Id 21을 hash key로 갖는 데이터 중에서 unique id가 21~25 사이에 있는 데이터를 가져오는 query를 수행해서 Unique Id가 13~25 사이의 데이터를 가져올 수 있습니다. 즉, DB에서는 지원하지 않지만, 스키마를 잘 설계하면, application layer에서 range query를 흉내내는 것은 가능합니다.


5. Secondary Index를 지원하는가?

  HBase의 경우 secondary index를 지원하지 않습니다. 따라서 Secondary index를 별도의 테이블로 생성해서 직접 관리해 줘야 하는 부담이 있습니다. 반면에, DynamoDB는 Local/Global Secondary Index 2가지를 지원하고 있습니다. 

  Local Secondary Index는 메인 테이블과 별개로 테이블이 생성되는 것은 아니고, 데이터를 저장하는 물리적인 node의 local storage에 색인 데이터가 생성되는 것입니다. 그리고 Local Secondary Index의 경우, 최대 10GB까지 데이터를 저장할 수 있습니다. 

  하지만 Global Secondary Index는  메인 테이블과 별개로 새로운 테이블이 생성되고, 메인 테이블의 일부 item들을 projection한 결과를 저장할 수 있습니다. 또한, Global Secondary Index는 메인 테이블의 내용이 변경될 경우, 데이터를 자동으로 동기화되는 장점이 있습니다.

  DynamoDB의 Secondary Index 기능은 매우 좋은 기능이지만, 다음과 같은 단점도 존재합니다.

 a. Loca/Global Secondary Index를 각각 테이블당 최대 5개까지 밖에 생성할 수 없습니다. 

 b. 테이블을 생성할 때, Secondary Index를 생성해 줘야 하며, 테이블 생성 완료 후, 변경이 불가능합니다. 만약 테이블이 생성된 후, Secondary Index를 추가하고 싶다면, 다른 테이블을 만든 다음, 데이터를 모두 옮겨줘야 합니다.

 c. Secondary Index가 추가될 때마다, write capacity가 감소합니다. 만약 Secondary Index가 없다면, 테이블에 1회 write operation을 수행한다면, 1번의 write만 일어나지만, Secondary Index가 있다면, Secondary Index 개수만큼 write가 추가적으로 발생하게 됩니다. 따라서 동일한 write capacity 상에서 Secondary Index를 추가할수록 사용 가능한 write operation은 그만큼 줄어들게 됩니다. (=돈이 많이 듭니다) 그러므로 불필요한 Secondary Index는 되도록 만들지 않는 것이 신상에 좋습니다.


6. Schema 변경이 자유로운가?

  DynamoDB 역시 다른 NoSQL 처럼, schemaless 하므로, schema 변경은 자유롭습니다. 하지만 하나의 테이블에 저장되는 item의 크기 (RDS의 row size와 같음)에는 64KB를 초과할 수 없습니다. HBase의 경우, 이론상 하나의 row에 저장할 수 있는 column 수에 제한이 없지만, DynamoDB의 경우, 한 item에 저장되는 데이터의 크기가 64KB를 넘지 않도록 주의해야 합니다.


7. TTL(Time-To-Live)을 지원하는가?

   HBase의 경우, TTL을 설정해서 일정 기간 이상 지난 오래된 데이터는 자동 삭제할 수 있도록 할 수 있지만, 현재까지 DynamoDB는 TTL을 지원하고 있지 않습니다. 많은 사용자들이  TTL 기능을 요구하고 있지만, 아직 AWS DynamoDB Team에서 지원해주지 못하고 있다고 합니다.

   따라서 TTL 기능이 필요한 경우, last modified time 과 같은 속성을 데이터에 추가해서 오래된 데이터는 사용자가 직접 삭제할 수밖에 없습니다. 로그 데이터와 같은 Time Series Data의 경우에는 일별, 주별 혹은 월별로 테이블을 별도로 생성한 후에, 오래된 데이터는 테이블 전체를 삭제하는 하는 편이 더 좋다고 합니다. 만약, 테이블을 시간 순서로 분리하지 않고, 하나의 테이블에 있는 오래된 데이터를 삭제할 경우, 삭제 연산 역시 write 연산이기 때문에 그만큼의 write capacity가 필요하고, 테이블 전체를 삭제하는 것보다 비효율적이라고 합니다.


8. Transaction을 지원하는가?

  MySQL과 같은 RDS를 사용하다가 HBase나 DynamoDB와 같은 NoSQL을 사용할 때, 가장 먼저 겪는 불편함은 mult-rows혹은 mutl-tables 간의 transaction 처리 일 것입니다. 대부분의 NoSQL은 scalibility를 위해서 transaction을 희생하고 있기 때문에, application개발 시에, transaction 이 필요하다다면, 난감한 상황에 처하게 됩니다.

  다행히 DynamoDB의 경우, mutl-rows transaction을 지원하는 java API를 제공하고 있습니다. Transaction 처리가 필요한 경우, 한 번쯤 검토를 해보시는 것도 좋을 것 같습니다. HBase의 경우, omidhaeinsa와 같은 transaction 기능을 지원하는 open source project가 진행 중이니 참고 하시기 바랍니다.


9. Multi-versioning 기능을 제공하는가?

   HBase의 경우, MAX_VERSION이라는 옵션을 사용해서, 여러 버전의 데이터를 저장할 수 있습니다. 예를 들어, MAX_VERSION을 3으로 설정하면, 동일한 row key에 대해서 최대 3개까지의 데이터를 저장하고, 버전별로 데이터를 읽어올 수 있습니다.

  DynamoDB의 경우, 아쉽게도 mult-versioning 기능을 지원하지 않기 때문에, (물론 내부적으로 multi-version을 이용해서 데이터를 관리합니다.) multi-versoning 기능이 필요한 경우, TTL과 마찬가지로 사용자가 직접 관리해줘야 하는 부담이 있습니다.


10. 쉽게 확장 가능한가?

  DynamoDB는 provisioned I/O를 보장해 주기 때문에, read/write throughput  필요에 따라서 scale-up 하기가 쉽습니다. AWS DynamoDB Console이나 Client API를 이용해서 쉽게 read/write throughput을 조정할 수 있습니다.

  하지만 scale-up은 임의대로 할 수 있지만, scale-down은 1일 4회로 제한되어 있습니다. 따라서 read/write peek 시점에만 일정 시간 동안 scale-up을 했다가, 다시 scale-down을 하고자 할 경우, 하루에 5번 이상 할 수 없습니다. 이런 경우에는 read/write 모니터링을 하면서, read/write 횟수를 일정하게 유지 할 수 있도록 시스템을 설계하는 것이 좋습니다. 그렇지 않을 경우, 요금 폭탄을 맞을 수도 있습니다. 

이상 10가지 정도 DynamoDB에 대해서 HBase와 비교하여 간략히 설명해 드렸습니다. DynamoDB의 경우, HBase가 지원하지 않는 좋은 장점들도 있지만, 데이터 모델의 차이 때문에 데이터의 접근 패턴에 따라서는 사용하기 어려운 부분도 있습니다.

언제나 그렇듯 정답은 없는 것 같습니다. 너무 뻔한 얘기지만, 역시 NoSQL을 사용하고잘 할 때는 NoSQL 마다의 특성을 잘 파악해서 사용 목적에 가장 잘 맞는 것을 선택해서 사용하는 것이 정답인 것 같습니다. ^^


[참고 자료]


Posted by recopick

댓글을 달아 주세요