DynamoDB

AWS에서 개발한 NoSQL 데이터베이스를 제공하는 서비스입니다.

(Document 모델, Key-Value 모델 모두 지원)

어떤 경우에 사용하면 될까..?

  • 읽기와 쓰기가 매우 빈번하고 처리 속도가 빨라야 하는 환경
  • 작은 용량의 데이터가 매우 많을 때
  • 고가용성(High Availability)의 분산 데이터베이스를 자체 운영하기 부담될 때

장점

  • AWS 생태계에 잘 통합이 되어 있습니다.
  • 완전 관리형 NoSQL 데이터베이스 서비스로 개발자가 분산 데이터베이스를 운영하고 크기 조정하는 데 따른 관리 부담을 줄여줍니다.
  • 용량에 맞게 테이블을 자동으로 확장/축소하는 Auto Scaling 기능을 통해 규모에 상관없이 사실상 무제한의 처리량, 저장 용량을 제공할 수 있습니다. 물론, 백업 및 복원의 기능도 제공을 합니다.

AWS에서 의미하는 완전관리형 서비스란?

AWS에서 모두 관리해주는 것을 말한다. 사용자가 DynamoDB 서비스를 이용하는데 있어서
내부적으로 서버/OS가 있지만 사용자에게는 드러나지 않아(서버리스 서비스) 관리할 서버가 필요 없고,
사용자는 설정만으로 또는 설정하지 않아도 쉽게 백업, 가용성에 대한 부분을 보장 받을 수 있습니다.

단점

  • ORM 지원 라이브러리도 없고, 있다 하더라도 메이저하지도 않아서 쓰기에 불안합니다.
  • 이런 상태에서 분량이 큰 REST API 서비스를 만드는데 있어 체계적인 API가 제공되지 않아 NoSQL쿼리 코드를 관리하는 관리 전략이 필수요소가 될겁니다.
  • 러닝커브

주요 개념

Table

DynamoDB에서도 데이터를 저장할 때 사용하는 테이블이라는 개념은 동일합니다.

Item (항목)

RDBMS(관계형 데이터베이스)에서의 row와 유사한 개념으로 테이블에 Insert, Update, Delete 하게 될 속성들의 집합을 의미합니다.

Attribute (속성)

RDBMS(관계형 데이터베이스)에서의 column과 유사한 개념으로 항목을 구성하는 각각의 데이터들을 의미합니다.

각 테이블에는 0개 이상의 항목이 들어갑니다.

Key를 제외한 테이블의 Attribute들은 미리 정의할 필요가 없습니다. (Key 내용은 아래 참고)

{
    "seq" : 1, // 기본키
    "userId" : 2,
    "userName" : "옙",
    "text" : "안녕하세요.",
    "registerDate" : "2022-05-18",
    "status" : 1,
}

// 각 항목에는 기본키가 있다. 여기서는 seq.
// 기본키(seq)를 제외하면 cheer 테이블에는 별도의 스키마가 없다.
// 이는 항목 내부의 속성이나 데이터 형식을 정할 필요가 없음을 의미하고 속성들은 얼마든지 늘어날 수 있다.
// 이 항목내 속성은 스칼라로서, 하나의 값만 가질 수 있다.

데이터 유형

  • Scalar type : 하나의 값만 표현합니다. 숫자, 문자열, Binary, Boolean, null
  • Document type : 트리 형태로 표현 가능한 중첩된 구조
  • Set type : 집합 (포함된 항목들은 고유해야 한다)
데이터 유형 상세

1. Scalar types

Number

최대 38자리까지 지원합니다. 이 제한을 초과할 시 예외가 발생합니다. DynamoDB에서 숫자는 가변 길이로 표현되며 0으로 시작하거나 끝나면 0은 잘립니다. (정해진 표현 범위를 벗어나는 만큼 0으로 끝나면 잘린다는 뜻으로 이해함.)
숫자형을 사용해 날짜 또는 타임스탬프를 표현할 수 있습니다. (예: 유닉스 시간)

String

문자열은 UTF-8 인코딩을 사용합니다. 문자열 길이는 0을 초과해야 하며, 다른 속성의 크기와 갯수에 따라 400KB의 최대 DynamoDB 항목 크기 제한으로 제약됩니다. 또한, 기본 키가 문자열이라면 다음과 같은 제약이 추가됩니다.
– 파티션 키의 최대 길이는 2KB
– 정렬 키의 최대 길이는 1KB
DynamoDB는 문자 코드 값의 크기로 문자열 비교를 수행합니다. “a”(0x61) 은 “A”(0x45)보다 큽니다.
문자열을 이용해도 날짜 혹은 타임스탬프를 표현할 수 있습니다. (예: ISO 8601)

Binary

실행 파일이나 압축 파일, 이미지와 같은 모든 이진 데이터를 저장하기 위한 타입입니다. 비교시에는 각 바이트를
unsigned char 로 간주한 다음 대소를 비교합니다. 크기는 문자열과 마찬가지로 0 초과, 항목 내 다른 속성의 크기에 따라 최대 400KB 제약을 갖습니다.
바이너리를 기본 키로 사용하는 경우에도 문자열과 같이 파티션 키일 경우 2KB, 정렬 키일 경우 1KB 제약을 갖습니다.
애플리케이션 상에서 바이너리 데이터를 DynamoDB로 보내기 전에는 Base64로 인코딩해야 합니다.

2. Document types

문서 타입에는 List와 Map이 있습니다. 이 둘은 서로 중첩 가능하며, 32단계까지 중첩 가능합니다. 리스트와 맵 안의 값의 갯수는 제한이 없지만 400KB의 항목 크기 제한은 초과하지 않아야 합니다.
속성 값에 빈 문자열이나 공집합은 허용되지 않지만, 빈 리스트나 빈 맵은 허용됩니다.

List

JSON 배열과 유사합니다. 순서가 지정된 값들의 모음입니다. 대괄호[…]로 묶습니다.
저장할 수 있는 데이터 형식에는 제한이 없어 한 리스트에 형식이 다른 요소도 함께 있을 수 있습니다.

Map

JSON 객체와 유사합니다. 정렬되지 않은 Key-value의 모음을 저장할 수 있으며 저장할 수 있는 데이터 형식에는 제한이 없어 한 맵에 형식이 다른 요소도 함께 있을 수 있습니다.
중괄호 {…}로 묶습니다.

3. Set types(집합)

숫자 집합, 문자열 집합, 이진수 집합을 지원합니다. 집합 내 모든 원소의 타입은 동일해야 합니다.
집합 내 값의 수에는 제한이 없지만, 400KB를 초과하지 않아야 합니다.
집합 내 원소들은 유일해야 합니다. 다만, 집합 내 값의 순서는 유지되지 않습니다.

Key (기본키)

테이블에는 항상 기본키가 있어야 합니다.
기본키 구성 방법은 크게 두가지로 나누어집니다.

  • 단일PK – 유니크한 하나의 속성을 Partition Key로 설정하여 Primary Key로 사용하는 방법으로 동일한 Partition Key를 가진 Item이 중복될 수 없음. (ex. user_id, contents_id)
  • 복합PK – 첫번째 속성은 Partition Key로 설정, 두번째 속성은 Sorting Key로 설정하여 조합해서 Primary Key로 사용하는 방법
    • 동일한 Partition Key 해시값으로 동일 영역에 같이 저장되지만 Sort Key로 분류된다.
    • 복수의 Item은 동일한 Partition Key 가능하나 Sort Key는 달라야 한다.
    • 활용: 동일한 userid를 가진 사용자가 복수의 글을 업로드 (user id + posting date)

Partition Key (파티션 키)

테이블을 생성할 때 필수적으로 설정을 해야하는 기본 키입니다.
하나의 Attribute로 구성되며 스칼라 데이터 형식만 가능합니다.
일치(Equal) 방식 검색만 지원합니다.(검색시, 정확히 일치하는 것만 조회)

Sorting Key (정렬 키)

테이블을 생성할 때 선택적으로 설정할 수 있는 기본 키입니다.
정렬 키는 동일한 파티션 키를 가진 데이터를 정렬할 때 쓰입니다.
범위를 지정할 수 있는 검색을 지원하는데 즉, between, >, <등 연산자를 사용하는 범위 쿼리를 사용하여 관련 항목의 필요한 그룹을 검색가능합니다.

파티션 키와 정렬 키는 기본 키임으로 생략할 수 없고, 또한 변경을 할 수 없어 주의가 필요합니다.

Secondary Index (보조 인덱스)

테이블에서 하나 이상의 보조 인덱스를 생성할 수 있습니다.

기본키에 대한 쿼리 및 대체키를 사용하여 데이터에 대한 쿼리를 실행할 수 있으며 보조 인덱스를 생성한 후에는 인덱스로 데이터를 읽을 수 있습니다.

하나의 key만으로는 다양한 어플리케이션의 요구사항을 만족시키기 어렵기 때문에 대부분 secondary index를 생성하여 사용합니다. (key는 string, number, binary중 하나여야합니다.)

Local Secondary Index (로컬 보조 인덱스)

  • 베이스 테이블과 동일한 파티션 키를 사용하지만 다른 정렬 키를 사용합니다.
  • 베이스 테이블 생성 시 지정. 이후에 추가, 삭제, 변경 불가능합니다.
  • 테이블당 최대 5개의 로컬 보조 인덱스 설정 가능하며, 하나의 파티션키 당 Index된 데이터는 10GB 미만이어야 합니다.

Global Secondary Index (글로벌 보조 인덱스)

  • 파티션키와 정렬키가 베이스 테이블의 key들과 달라도 됩니다.
  • 테이블 생성 시 지정. 이후에도 언제든지 생성, 삭제 가능합니다.
  • 테이블당 최대 20개까지 생성 가능하며, 하나의 파티션키 당 Index된 데이터는 제한이 없습니다.

Auto Scaling

실제 트래픽 패턴에 따라 사용자 대신 동적으로 조정합니다. 따라서 테이블 또는 글로벌 보조 인덱스에 따라 할당된 읽기 및 쓰기 용량을 늘려 병목 현상 없이 갑작스러운 트래픽 증가를 처리할 수 있습니다.
워크로드가 감소할 경우 사용하지 않는 용량에 대한 요금을 지불하지 않도록 처리량을 줄일 수 있습니다.

  • 테이블 생성시, Auto Scaling 활성화 여부에 대한 설정이 가능합니다.
  • 이미 생성된 테이블이라면, AWS Management Console을 사용하여 수정가능합니다.

Auto Scaling 프로세스

  1. 사용자가 DynamoDB 테이블에 대한 Application Auto Scaling 정책을 설정합니다.
  2. DynamoDB는 Amazon CloudWatch에 소비된 용량 지표를 게시합니다.
  3. 테이블에서 사용한 용량이 특정 기간의 목표 사용률을 초과하는 경우(또는 목표에 미달하는 경우), Amazon CloudWatch는 경보를 트리거합니다. 콘솔에서 이 경보를 확인하고 Amazon Simple Notification Service(Amazon SNS)를 사용하여 알림을 받을 수 있습니다.
  4. CloudWatch 경보를 받으면 크기 조정 정책을 평가하기 위해 Application Auto Scaling이 호출됩니다.
  5. Application Auto Scaling은 UpdateTable 요청을 실행하여 테이블의 할당된 처리량을 조정합니다.
  6. DynamoDB는 UpdateTable 요청을 처리하고 해당 테이블의 할당된 처리 용량을 동적으로 늘리거나 줄임으로써 목표 사용률에 근접하게 합니다.

TTL

데이터 유효기간을 의미하며 테이블 설정시 간단하게 설정 가능합니다.
데이터 삭제를 위한 연산 비용은 없으나 TTL 사용을 위해 부가적으로 사용된 데이터 저장 공간 비용은 청구됩니다.
TTL 시간은 최대 5년을 넘길 수 없습니다.

사용 방법

TTL을 표기할 Attribute(속성) 이름을 정의하고, 아이템 저장 시 해당 Attribute(속성)에 만료 기간을 함께 저장하면 됩니다.
TTL Attribute(속성)는 Number타입이어야 하며, 초 단위의 유닉스-타임(Unix-time)으로 만료 기간을 표시해야 한다.

동작 방식

DynamoDB는 TTL을 위해 파티션 별 2개의 백그라운드-프로세스를 운영한다.
첫번째 프로세스는 테이블을 스캔하며 현재 시간과 만료 기간 비교하여, 만료된 아이템을 표시한다.
두번째 프로세스는 테이블을 스캔하며 첫번째 프로세스가 표시한 만료된 아이템을 찾아 삭제한다.

다만, 유의할 점이 있다!!

  • TTL 만료 데이터 삭제 시점
    위에 동작 방식으로, 유저가 정의한 TTL 설정 시간과 실제 데이터가 삭제되는 시간 사이에는 간격이 발생할 수 있다.
    그리고 이러한 간격은 테이블 파티션의 크기와 파티션에서 사용한 연산양에 비례하여 커질 것이다. (TTL도 파티션에 할당된 제한된 자원을 사용하여 동작하기 때문)
    이러한 시간 간격은 최대 48시간까지 발생할 수 있다고 AWS는 정의하고 있다.
  • 만료된 아이템의 읽기 쓰기
    만료된 데이터는 최대 48시간까지 지연되어 삭제될 수 있는데 이 뜻은 유저가 만료된 데이터에 여전히 읽기, 쓰기 연산을 적용할 수 있음을 의미한다.
    즉, TTL만 믿으면 안되고 올바른 데이터 조회 및 처리를 위해서는 반드시 현재 시간 기준으로 만료된 시간을 계산하고 필터 조건을 포함하여야 한다.
    필터가 없다면 데이터 조회 시 만료된 데이터가 함께 조회되는 낭패를 볼 수 있다.
    또한, 이미 만료된 데이터에 TTL 어트리뷰트를 업데이트하여 연장하거나 TTL 어트리뷰트를 삭제하여 TTL을 비활성화 할 수도 있다.

테이블 구조 설계 간단하게, 클라이언트 툴, 읽기 모드에 대한 상황 판단

Reference

안녕하세요. 끄적이기를 좋아하는 개발자 이예빈입니다. 매일 일기를 쓰는 것 처럼 블로그를 쓰고 싶어요.