1. DynamoDB란?

요즘 세상은 온통 NoSQL이죠.

MongoDB, Riak, HBase, Cassandra, Neo4j, CouchDB, 그리고 DynamoDB...

DynamoDB는 일반 RDB의 확장성을 극복하기 위해 아마존이 만든 DB입니다.


2. 특성

그러면 NoSQL은 무엇인지, 또 왜 NoSQL인지, DynamoDB의 특성은 무엇인지 간단히 알아보겠습니다.

  • 기존 RDB의 특성은 ACID, 트랜잭션 기반, Rich 쿼리, 조인(Join)으로 대표되었습니다만.
  • NoSQL은 RDB의 ACID에 대응하는 BASE라는 특성은 갖고 있죠. BASE는 Basically Available, Soft state, Eventually Consistent의 약자이다.
  • 정확한 일관성과 데이터의 즉시 반영을 포기하는 대신 확장성을 특징으로 한다.
  • SNS, 게임, 미디어, IoT등 웹 규모의 애플리케이션에 적합하다.
  • 스키마가 없다. 각 테이블은 각각의 데이터 항목을 고유하게 식별하는 기본 키가 필요하다.
  • Management Console 혹은 CLI를 통해 작업할 수 있다. 애플리케이션의 경우 SDK를 통해 접근할 수 있다.
  • 분산 하드웨어 클러스터를 통해 확장할 수 있다.
  • 처리량을 프로비저닝할 수 있다. Read, Write 각각 필요한 만큼의 처리 용량을 할당한다. 예를 들어 Read가 강한 시스템이라면 Read 1000, Write 100, 일반적인 시스템이라면 Read 500, Write 500 등으로 설정 가능하다. 이 값은 DB 운영 중에 온라인으로 변경 가능하다. (단 스케일 다운의 경우 제한있음)
  • 요금체계는 1) 처리량 (시간당) 요금, 2) 스토리지 (GB당) 요금이 있다.
  • 하나의 아이템은 하나 이상의 속성(attribute)을 가질 수 있다.
  • 한번 생성된 인덱스는 삭제할 수 없다.
  • OCC(optimistic concurrency control)를 지원한다.
  • Atomic update를 지원한다.
  • 단일 테이블 단위로 처리 시 만약 초당 10,000 쓰기 혹은 초당 10,000 읽기 이상이 발생한다면 미리 AWS를 컨텍하는 것이 좋다.

3. 개념

  • Table : Item의 모음
  • Item : Key와 하나 이상의 Attribute
  • Attribute : Name과 Value를 가짐

4. Conditional write

PutItem, UpdateItem, DeleteItem 등은 기본적으로 Unconditional write 방식이다. 하지만 옵셔널하게 Conditional write도 지원한다.

Conditional write는 항목 속성이 하나 이상의 예상 조건과 일치하는 경우에만 성공합니다. 그렇지 않으면 오류를 반환합니다. 이는 많은 상황에서 유용합니다. 예를 들면 동일한 기본 키가 있는 항목이 아직 없는 경우에만 PutItem 작업이 성공하도록 하려고 합니다. 또는 속성 중 하나에 특정 값이 있으면 UpdateItem 작업을 통해 항목을 수정할 수 없도록 할 수 있습니다.


5. 사용

먼저 테이블의 키와 인덱스를 결정하고, Read/Write 처리량을 결정합니다.

동작은 HTTP API로 제공하는데, API의 종류는 다음과 같습니다.

  • PutItem
  • UpdateItem
  • GetItem
  • DeleteItem
  • BatchWriteItem
  • BatchGetItem : 하나 이상의 테이블에서 하나 이상의 아이템을 요청할 수 있다. 단, 100 아이템 이상을 요청하면 ValidationException (Too many items requested for the BatchGetItem call) 발생
  • CreateTable
  • DescribeTable
  • UpdateTable
  • DeleteTable
  • Query (Hash + 범위키 조회)
  • Scan (전체 테이블 조회)

참고로 BatchDeleteItem이라는 것은 없습니다.

물론 SDK를 사용하는게 훨씬 편합니다. SDK는 자바, 파이선, PHP, 닷넷, 루비, 노드, 안드로이드, iOS 등과 연계 가능합니다.


6. 타입

  • 스칼라 데이터 타입 : String, Number, Binary
  • 멀티 밸류 타입 : String Set, Number Set, Binary Set

7. 기본 키

다음 두 유형의 키를 가질 수 있습니다.

  • Hash Key : Hash Key 단위로 데이터를 고유하게 식별 가능한 경우에 사용
  • Hash Key + Range Key : Hash Key에 해당하는 여러 데이터에서 Range Key로 검색 가능

키와 인덱스 종류는 다음과 같습니다.

  • Local secondary index
  • Hash primary key
  • Global secondary index 

8. 비용

  • 프로비저닝된 쓰기 처리량
  • 프로비저닝된 읽기 처리량
  • 인덱싱된 데이터 스토리지

9. 사례

9.1. 분석 시스템

수퍼셀의 게임 분석 시스템에 DynamoDB가 들어가 있는데, Kinesis로 수집된 데이터 저장 및 질의에 사용된다. (Kinesis는 일 450억건의 데이터를 수집한다고 함)

9.2. 데이터 저장

MySQL을 이용하여 시계열 데이터를 저장, 검색하는 애플리케이션을 DynamoDB로 변경하여 사용한 경우가 있다. 사실 DB 자체의 변경이 중요한게 아니라 OpsWorks를 통해 DynamoDB, EC2, LB 등을 포함한 Application stack을 구성했다고 한다.


10. Tomcat Session Cluster용

10.1. 관련 링크 및 다운로드

10.2. Tomcat 설정 추가

    <Manager className="com.amazonaws.services.dynamodb.sessionmanager.DynamoDBSessionManager"
             createIfNotExist="true" />

10.3. Tomcat 버전

Tomcat 8+ 이어야 한다. Tomcat 7에서는 오류가 발생하였다.

2월 09, 2018 10:32:29 오전 org.apache.catalina.core.StandardContext startInternal
심각: The session manager failed to start
org.apache.catalina.LifecycleException: Failed to initialize component [com.amazonaws.services.dynamodb.sessionmanager.DynamoDBSessionManager[]]
    at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:107)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:135)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5642)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:1015)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:991)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:652)
    at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1296)
    at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:2038)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:473)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1152)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:622)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NoSuchMethodError: com.amazonaws.services.dynamodb.sessionmanager.DynamoDBSessionManager.getContext()Lorg/apache/catalina/Context;
    at com.amazonaws.services.dynamodb.sessionmanager.DynamoDBSessionManager.getSessionConverter(DynamoDBSessionManager.java:245)
    at com.amazonaws.services.dynamodb.sessionmanager.DynamoDBSessionManager.createSessionStorage(DynamoDBSessionManager.java:241)
    at com.amazonaws.services.dynamodb.sessionmanager.DynamoDBSessionManager.initInternal(DynamoDBSessionManager.java:134)
    at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102)
    ... 13 more

10.4. DynamoDB 테이블

리전을 지정하지 않으면 버지니아에 Tomcat_SessionState라는 테이블이 생성된다. 리전 지정은 RegionId를 사용한다. 예를 들어 싱가포르에 만들고자 하면 context.xml의 Manager 설정에 RegionId="ap-southeast-1" 를 추가한다.