분산처리를 위해서 만들어진 NoSql - DynamoDB
- 태생적으로 분산 처리를 고려하여 만든 Database
- 데이터의 규모와 관계없이 일관되게, 수 밀리초 미만의 응답시간, 사실상 무제한의 처리량
- 관계형 데이터베이스의 장점인 보조인덱스와 트랜젝션 제공함
- 백업 복원도 쉬움
[ AWS Docs ] DynamoDB local 사용 참고 사항, 컴퓨터에 로컬로 DynamoDB 배포
SDK
- AWS SDK for Java 2.x (High level api) : DynamoDBEnhancedClient API, Use advanced mapping features
- DynamoDbBean 어노테이션 사용하기
- [Blog ] Using Dynamodb with Kotlin + Spring Boot
- [ Git issue ] DynamoDB Enhanced Client support for Immutable objects
- [ AWS Docs ] Work with nested attributes
- AWS SDK for Java 2.x (Low level api) : DynamoDBClient
테이블 정의
- primary key 를 정해주어야 함. 고유한 값
데이터 CRUD 종류
[ AWS Docs ] Working with items and attributes
GetItem
: partition key 와 sort key를 명시해야 함(해당 테이블에 sort key가 있다면) 아이템 한개 가져오기
BatchGetItem
: Read up to 100 items from one or more tables
Query
: 특정 partition key를 갖고 있는 아이템들을 조회
- GetItem, Query, Scan, BatchGetItem


대용량 데이터 처리
- scale up
- CPU 분산(Read replica)
- 캐쉬 계층
- 하나의 물리적 서버에서 처리하기엔 점점 힘듦을 느끼게 됨
- 샤드? 그러나 샤드를 하게되면 운영에서 많은 어려움을 마주하게됨. 백업 복원도 어려워지고
조회
[ AWS Docs ] Working with scans in DynamoDB, 표현식 및 조건 사용, Comparison operator and function reference
- Query : PartitionKey가 필요, GSI(PK + optional sortkey)를 이용해서도 가능함
- scan : 풀 스캔
GSI를 이용한 조회
// 기본 GSI 조회 QueryConditional.keyEqualTo { key -> key.partitionValue(email) } // GSI + SortKey 조건 QueryConditional.sortBeginsWith { key -> key.partitionValue(email).sortValue(status) } QueryConditional.sortBetween { key -> key.partitionValue(email).sortValue(startDate, endDate) }
보조 인덱스
글로벌 보조 인덱스
로컬 보조 인덱스(LSI)는 추가 비용이 들지 않는 반면에, 얘는 WCUs가 2배가 됨. base table에다가 쓰고, global secondary index를 위한 테이블에도 한번 더 써야하기 때문에
GameScores 라는 테이블이 있을 때, 파티션 키(UserId), 정렬 키(GameTitle)이라고 하면

키 속성(UserId, GameTitle)을 지정한 쿼리는 매우 효율적. 그러나 애플리케이션에서 GameTitle 만을 토대로 GameScores 에서 데이터를 검색해야 할 경우에는 Scan 작업을 사용해야 함(비효율적)
키가 아닌 속성에 대한 쿼리 속도를 높이기 위해 글로벌 보조 인덱스를 만들 수 있고 글로벌 보조 인덱스는 기본 테이블의 속성 중 일부를 포함하지만 테이블과 다른 기본 키를 기준으로 구성.
예로, 파티션 키가 GameTitle 이고 정렬 키가 TopScore 인 GameTitleIndex 라는 글로벌 보조 인덱스를 생성할 수 있음
코틀린에서 정의하기
@DynamoDbBean data class Currency( // KSUID @get:DynamoDbAttribute("id") var id: String = "", // Primary Key // pk-currencyCode-contryCode-sk-timestamp @get:DynamoDbPartitionKey @get:DynamoDbAttribute("PK") var pk: String = "", @get:DynamoDbAttribute("currency_code") @get:DynamoDbSecondaryPartitionKey(indexNames = ["gsi-pk-currency-code-sk-timestamp"]) var currencyCode: String = "", @get:DynamoDbAttribute("contry_code") var contryCode: String = "", @get:DynamoDbAttribute("value") var value: BigDecimal = BigDecimal.ZERO, @get:DynamoDbSortKey @get:DynamoDbAttribute("timestamp") @get:DynamoDbSecondarySortKey(indexNames = ["gsi-pk-currency-code-sk-timestamp"]) var timestamp: String = "" )
- DynamoDB의 엔티티 클래스에는
@DynamoDbBean
을 명시한다.
- 각 애트리뷰트와 필드를 맵핑하기 위한 정보로서
@DynamoDbAttribute
을 명시할 수 있다. 이를 통해 물리적인 애트리뷰트의 이름과 필드명을 다르게 할 수 있다.
- Primary Key(PK)의 Partition Key(PK)에 해당하는 필드에는
@DynamoDbPartitionKey
를 명시한다. 마찬가지로 Primary Key(PK)의 Sort Key(SK)에 해당하는 필드에는@DynamoDbSortKey
를 명시한다.
- GSI에는 앞서 PK와 유사하게
@DynamoDbSecondaryPartitionKey
와@DynamoDbSecondarySortKey
를 명시한다.
- LSI 에는
@DynamoDbSecondarySortKey
와 인덱스 이름을 명시
로컬 보조 인덱스

PartitionKey가 ForumName, Subject가 sortKey인 상태에서 아래와 같은 데이터 액세스 패턴이 필요할때
- 보기 및 회신 횟수가 가장 많은 포럼 스레드
- 특정 포럼에서 메시지 수가 가장 많은 스레드
- 특정 기간 동안 특정 포럼에 게시된 스레드 수
다른 인덱스가 없다면 테이블 전체를 Scan 해야 함
하지만,
Replies
또는 LastPostDateTime
같이 키가 아닌 속성에 하나 이상의 LocalSecondaryIndex 를 지정 가능 → 로컬 보조 인덱스의 데이터는 기본 테이블과 동일한 파티션 키를 기준으로 구성되지만, 다른 정렬 키를 사용 → Queryt작업에서 정렬키로 LastPostDateTime을 사용하여 데이터를 빠르게 찾을 수 있음로컬인덱스는 바로바로 동기적으로 작업되고
글로벌인덱스는 비동기적으로 값이 들어가고.
로컬보조인덱스는 테이블 만들때 만들어야 하고
글로벌보조인덱스는 중간에 만들수 있음
scan은 풀 서치고
query는 인덱스 사용해서 데이터가져오는 거고