DynamoDB의 데이터 모델링 빌딩 블록 - Amazon DynamoDB

DynamoDB의 데이터 모델링 빌딩 블록

이 섹션에서는 애플리케이션에 사용할 수 있는 설계 패턴을 제공하는 빌딩 블록 계층을 다룹니다.

데이터, 데이터 아래 있는 블록, 블록 아래 있는 기초 간의 개념적 관계를 보여주는 이미지. 기초를 강조.

복합 정렬 키 빌딩 블록

NoSQL을 비관계형이라고 생각할 수도 있습니다. 궁극적으로 관계를 DynamoDB 스키마에 배치하지 못할 이유는 없습니다. 관계는 관계형 데이터베이스 및 그 외래 키와 다르게 보일 뿐입니다. DynamoDB에서 데이터의 논리적 계층 구조를 개발하는 데 사용할 수 있는 가장 중요한 패턴 중 하나는 복합 정렬 키입니다. 가장 일반적인 설계 스타일은 계층 구조의 각 계층(부모 계층 > 자식 계층 > 손자 계층)을 해시태그로 구분하는 것입니다. 예를 들면 PARENT#CHILD#GRANDCHILD#ETC입니다.

userID가 프라이머리 키이고 다른 속성들의 조합이 정렬 키인 테이블의 항목을 보여 주는 이미지.

DynamoDB에서 데이터를 쿼리하려면 파티션 키에 항상 정확한 값이 필요하지만, 이진 트리를 통과하는 것과 비슷하게 왼쪽부터 오른쪽으로 정렬 키에 부분적 조건을 적용할 수 있습니다.

위의 예에는 사용자 세션에서 유지해야 하는 장바구니가 있는 전자 상거래 상점이 있습니다. 사용자가 로그인할 때마다 나중을 위해 저장된 항목을 포함하여 전체 장바구니를 보고 싶어 할 수 있습니다. 하지만 사용자가 결제에 들어갈 때는 구매를 위해 활성 장바구니에 있는 항목만 로드되어야 합니다. 이 두 KeyConditions는 모두 명시적으로 CART 정렬 키를 요청하므로 DynamoDB는 읽기 시 추가 위시리스트 데이터를 무시합니다. 저장된 항목과 활성 항목은 모두 동일한 장바구니의 일부이지만 애플리케이션의 서로 다른 부분에서 서로 다르게 처리해야 하므로 정렬 키의 접두사에 KeyCondition을 적용하는 것이 애플리케이션의 각 부분에 필요한 데이터만 검색하는 가장 최적화된 방법입니다.

이 빌딩 블록의 주요 특징

  • 효과적인 데이터 액세스를 위해 관련 항목들이 서로에 대해 로컬로 저장됩니다

  • KeyCondition 식을 사용하면 계층 구조의 하위 집합을 선택적으로 검색할 수 있으므로 낭비되는 RCU가 없습니다

  • 애플리케이션의 서로 다른 부분이 특정 접두사 아래 항목을 저장하여 항목 덮어쓰기나 쓰기 충돌을 방지합니다

멀티테넌시 빌딩 블록

많은 고객이 DynamoDB를 사용하여 멀티테넌트 애플리케이션의 데이터를 호스팅합니다. 이런 시나리오에서 단일 테넌트의 모든 데이터를 테이블의 자체 논리적 파티션에 보관하는 방식으로 스키마를 설계하려 합니다. 이 설계는 동일한 파티션 키를 가진 DynamoDB 테이블의 모든 항목을 가리키는 용어인 항목 컬렉션이라는 개념을 활용합니다. DynamoDB의 멀티테넌시 접근 방식에 대한 자세한 내용은 Multitenancy on DynamoDB를 참조하세요.

멀티테넌트 사진 사이트를 나타낼 수 있는 테이블을 보여 주는 이미지. 프라이머리 키는 파티션 키인 사용자와 정렬 키인 다양한 사진으로 구성됩니다. 각 항목의 속성에 사진이 호스팅되는 URL이 표시됩니다.

이 예제에서는 사용자가 수천 명인 사진 호스팅 사이트를 운영 중입니다. 각 사용자는 처음에는 자신의 프로필에만 사진을 업로드하지만 기본적으로 사용자가 다른 사용자의 사진을 보는 것을 허용하지 않을 것입니다. 각 사용자의 API 직접 호출 승인에 추가 격리 수준을 추가하여 해당 사용자가 자신의 파티션에서만 데이터를 요청하도록 하는 것이 이상적이지만 스키마 수준에서는 고유한 파티션 키로도 충분합니다.

이 빌딩 블록의 주요 특징

  • 한 사용자 또는 테넌트가 읽는 데이터 양은 해당 파티션에 있는 항목의 총량을 초과할 수 없습니다

  • 계정 폐쇄나 규정 준수 요청으로 인한 테넌트의 데이터 삭제를 요령 있고 저렴하게 수행할 수 있습니다. 파티션 키가 테넌트 ID와 같은 쿼리를 실행한 다음 반환된 각 프라이머리 키에 대해 DeleteItem 작업을 실행하기만 하면 됩니다.

참고

멀티테넌시를 염두에 두고 설계되었으므로 단일 테이블에서 다양한 암호화 키 제공자를 사용하여 데이터를 안전하게 격리할 수 있습니다. AWS Amazon DynamoDB용 데이터베이스 암호화 SDK를 사용하면 DynamoDB 워크로드에 클라이언트측 암호화를 포함할 수 있습니다. 속성 수준 암호화를 수행하여 DynamoDB 테이블에 저장하기 전에 특정 속성 값을 암호화하고, 전체 데이터베이스를 미리 해독하지 않고도 암호화된 속성을 검색할 수 있습니다.

희소 인덱스 빌딩 블록

액세스 패턴에서 드문 항목 또는 상태를 수신하는 항목(에스컬레이션된 응답 필요)과 일치하는 항목을 찾아야 하는 경우가 있습니다. 전체 데이터 세트에서 이러한 항목을 정기적으로 쿼리하는 대신 글로벌 보조 인덱스(GSI)에 데이터가 드물게 로드된다는 사실을 활용할 수 있습니다. 즉, 인덱스에 속성이 정의된 기본 테이블의 항목만 인덱스에 복제하는 것입니다.

대량의 안정 상태 데이터를 수신하는 기본 테이블을 보여 주는 이미지
에스컬레이션된 항목만 수신하는 글로벌 보조 인덱스를 보여 주는 이미지

이 예제에서는 현장의 각 디바이스가 정기적으로 상태를 보고하는 IoT 사용 사례를 볼 수 있습니다. 대부분의 보고서에서는 모든 것이 정상이라고 디바이스가 보고하기를 기대하지만, 때때로 고장이 발생할 수 있으며, 고장은 수리 기술자에게 에스컬레이션해야 합니다. 보고서에 에스컬레이션이 있으면 EscalatedTo 속성이 항목에 추가되지만 없다면 이 속성이 나타나지 않습니다. 이 예제의 GSI는 EscalatedTo를 기준으로 파티셔닝되며, GSI가 기본 테이블에서 키를 가져오므로 어떤 DeviceID가 언제 고장을 보고했는지 여전히 알 수 있습니다.

DynamoDB에서는 읽기가 쓰기보다 저렴하지만, 특정 항목 유형의 인스턴스가 드물면서도 이를 찾기 위한 읽기는 흔한 사용 사례에서 희소 인덱스는 매우 강력한 도구입니다.

이 빌딩 블록의 주요 특징

  • 희소 GSI의 쓰기 및 스토리지 비용은 키 패턴과 일치하는 항목에만 적용되므로 모든 항목이 복제되는 다른 GSI보다 GSI 비용이 훨씬 저렴할 수 있습니다.

  • 복합 정렬 키를 사용하면 원하는 쿼리와 일치하는 항목의 범위를 더욱 좁힐 수 있습니다. 예를 들어 정렬 키에 타임스탬프를 사용하여 지난 X분 동안 보고된 고장을 볼 수 있습니다(SK > 5 minutes ago, ScanIndexForward: False).

TTL(Time To Live) 빌딩 블록

대부분의 데이터에는 해당 데이터를 기본 데이터 스토어에 보관할 가치가 있다고 간주되는 일정한 기간이 있습니다. 오래된 데이터를 쉽게 제거할 수 있도록 DynamoDB에는 TTL(Time to Live)이라는 기능이 있습니다. TTL 기능을 사용하면 (과거의) epoch 타임스탬프가 있는 항목에 대한 모니터링이 필요한 특정 속성을 테이블 수준에서 정의할 수 있습니다. 이렇게 하면 만료된 레코드를 무료로 테이블에서 삭제할 수 있습니다.

참고

글로벌 테이블의 글로벌 테이블 버전 2019.11.21(현재)을 사용하고 Time To Live 기능도 사용한다면 DynamoDB는 TTL 삭제를 모든 복제본 테이블에 복제합니다. 최초 TTL 삭제는 TTL 만료가 발생하는 리전의 쓰기 용량을 사용하지 않습니다. 그러나 복제본 테이블에 복제되는 TTL 삭제는 각 복제본 리전의 복제된 쓰기 용량을 사용하며, 해당 요금이 적용됩니다.

TTL(Time To Live) 속성이 있는 사용자 메시지가 포함된 테이블을 보여 주는 이미지

이 예제에는 사용자가 짧은 수명의 메시지를 생성할 수 있도록 설계된 애플리케이션이 있습니다. DynamoDB에서 메시지가 생성되면 애플리케이션 코드에 의해 TTL 속성이 7일 후 날짜로 설정됩니다. 약 7일 후, DynamoDB는 이러한 항목의 에포크 타임스탬프가 과거임을 확인하고 삭제합니다.

TTL을 통한 삭제는 무료이므로 이 기능을 사용하여 테이블에서 기록 데이터를 제거하는 것이 좋습니다. 이렇게 하면 매달 전체 스토리지 요금이 줄어들고, 사용자 쿼리를 통해 검색되는 데이터가 줄어들기 때문에 사용자 읽기 비용도 절감할 수 있습니다. TTL은 테이블 수준에서 활성화되어 있지만 어떤 항목이나 엔터티에 TTL 속성을 생성할지와 에포크 타임스탬프를 얼마나 먼 장래로 설정할지는 사용자에게 달려 있습니다.

이 빌딩 블록의 주요 특징

  • TTL 삭제는 테이블 성능에 영향을 주지 않고 백그라운드에서 실행됩니다.

  • TTL은 대략 6시간마다 실행되는 비동기 프로세스이지만 만료된 레코드를 삭제하는 데는 48시간 이상 걸릴 수 있습니다.

    • 오래된 데이터를 48시간 이내에 정리해야 하는 경우, 잠금 기록이나 상태 관리 같은 사용 사례에서 TTL 삭제를 사용하지 마세요.

  • TTL 속성에 유효한 속성 이름을 지정할 수 있지만 값은 숫자 유형이어야 합니다.

아카이브용 TTL(Time To Live) 빌딩 블록

TTL은 DynamoDB에서 오래된 데이터를 삭제하는 데 효과적인 도구이지만, 기본 데이터 스토어보다 더 긴 기간 동안 데이터 아카이브를 보관해야 하는 사용 사례가 많습니다. 이 경우 TTL의 시간 설정된 레코드 삭제를 활용하면 만료된 레코드를 장기 데이터 스토어로 푸시할 수 있습니다.

TTL(Time To Live) 삭제 작업을 DynamoDB Streams로 전송한 다음 장기 데이터 스토어로 전송하는 테이블을 보여 주는 이미지.

DynamoDB가 TTL 삭제를 수행하면 삭제 작업은 DynamoDB Stream에도 Delete 이벤트로 푸시됩니다. 하지만 DynamoDB TTL이 삭제를 수행하는 경우, principal:dynamodb의 스트림 레코드에 속성이 있습니다. DynamoDB Stream의 Lambda 구독자를 사용하면 DynamoDB 보안 주체 속성에만 이벤트 필터를 적용할 수 있으며, 해당 필터와 일치하는 모든 레코드가 S3 Glacier 같은 아카이브 스토어로 푸시된다는 것을 알 수 있습니다.

이 빌딩 블록의 주요 특징

  • 기록 항목에 대해 지연 시간이 짧은 DynamoDB 읽기가 더 이상 필요하지 않게 되면 해당 항목을 S3 Glacier와 같은 콜드 스토리지 서비스로 마이그레이션하여 사용 사례의 데이터 규정 준수 요구 사항을 충족하는 동시에 스토리지 비용을 크게 줄일 수 있습니다.

  • 데이터가 Amazon S3에 보관되는 경우, Amazon Athena나 Redshift Spectrum 같은 비용 효율적인 분석 도구를 사용하여 데이터의 기록 분석을 수행할 수 있습니다.

수직 파티셔닝 빌딩 블록

문서 모델 데이터베이스에 익숙한 사용자라면 모든 관련 데이터를 단일 JSON 문서에 저장한다는 개념에 익숙할 것입니다. DynamoDB는 JSON 데이터 유형을 지원하지만 중첩된 JSON에서의 KeyConditions 실행은 지원하지 않습니다. 디스크에서 읽는 데이터의 양과 쿼리가 실제로 사용하는 RCU 수를 결정하는 것은 KeyConditions이므로 규모가 커지면 비효율성이 초래될 수 있습니다. DynamoDB의 쓰기 및 읽기를 더 잘 최적화하려면 문서의 개별 엔터티를 개별 DynamoDB 항목으로 분리하는 것이 좋습니다. 이를 수직 파티셔닝이라고도 합니다.

중첩된 JSON 객체로 포맷된 대규모 데이터 구조를 보여 주는 이미지.
항목의 정렬 키가 DynamoDB 사용량 최적화에 도움이 되는 항목 컬렉션을 보여 주는 이미지.

위에 나온 것처럼 수직 파티셔닝은 실제 단일 테이블 설계의 주요 예이지만 원하는 경우 여러 테이블에 걸쳐 구현할 수도 있습니다. DynamoDB는 1KB 단위로 쓰기 요금을 청구하므로 항목이 1KB 미만이 되는 방식으로 문서를 파티셔닝하는 것이 좋습니다.

이 빌딩 블록의 주요 특징

  • 데이터 관계의 계층 구조는 정렬 키 접두사를 통해 유지되므로 필요한 경우 클라이언트측에서 단일 문서 구조를 다시 구축할 수 있습니다.

  • 데이터 구조의 단일 구성 요소를 독립적으로 업데이트할 수 있으므로 작은 항목 업데이트의 WCU는 1에 불과합니다.

  • 정렬 키 BeginsWith를 사용하면 애플리케이션이 단일 쿼리로 유사한 데이터를 검색할 수 있으므로 줄어든 총 비용/지연 시간에 대해 읽기 비용이 집계됩니다.

  • 큰 문서는 DynamoDB의 개별 항목 크기 제한인 400KB를 쉽게 초과할 수 있으며, 수직 파티셔닝으로 이 제한을 피할 수 있습니다.

쓰기 샤딩 빌딩 블록

DynamoDB에 있는 몇 안 되는 엄격한 제한 중 하나는 단일 물리적 파티션이 초당 유지할 수 있는 처리량(단일 파티션 키일 필요는 없음)에 대한 제한입니다. 이러한 제한은 현재 다음과 같습니다.

  • 1,000WCU(또는 1KB 이하 항목 초당 쓰기 1,000회) 및 3,000 RCU(또는 4KB 이하 초당 읽기 3,000회)의 강력한 일관성 또는

  • 4KB 이하 초당 읽기 6,000회의 최종 일관성

테이블에 대한 요청이 이러한 제한 중 어느 하나라도 초과하는 경우, ThroughputExceededException의 클라이언트 SDK에 오류가 다시 전송되는데, 이를 보다 일반적으로는 제한(throttling)이라고 합니다. 이 제한을 초과하는 읽기 작업이 필요한 사용 사례에서는 대부분 DynamoDB 앞에 읽기 캐시를 배치하는 것이 가장 좋지만 쓰기 작업에는 쓰기 샤딩이라는 스키마 수준 설계가 필요합니다.

DynamoDB가 여러 파티션에 파티션 키를 샤딩하여 트래픽 급증으로 인한 제한을 방지하는 방법을 보여 주는 이미지.
DynamoDB가 여러 파티션에 파티션 키를 샤딩하여 트래픽 급증으로 인한 제한을 방지하는 방법을 보여 주는 이미지.

이 문제를 해결하기 위해 애플리케이션의 UpdateItem 코드에서 각 참가자의 파티션 키 끝에 무작위 정수를 추가하겠습니다. 난수 생성기의 범위는 주어진 참가자의 초당 예상 쓰기 횟수를 1,000으로 나눈 값과 일치하거나 초과하는 상한값을 가져야 합니다. 초당 20,000회의 투표를 지지하기 위해 이 값은 rand(0,19)처럼 보일 것입니다. 이제 데이터가 별도의 논리적 파티션에 저장되었으므로 읽을 때 데이터를 다시 결합해야 합니다. 투표 합계가 실시간일 필요는 없으므로 X분마다 모든 투표 파티션을 읽도록 예약된 Lambda 함수가 각 참가자에 대해 집계를 때때로 수행하여 실시간으로 읽을 수 있도록 단일 투표 합계 레코드에 다시 쓸 수 있습니다.

이 빌딩 블록의 주요 특징

  • 특정 파티션 키의 매우 높은 쓰기 처리량이 불가피한 사용 사례의 경우, 여러 DynamoDB 파티션에 쓰기 작업을 인위적으로 분산할 수 있습니다.

  • 카디널리티가 낮은 파티션 키가 있는 GSI도 이 패턴을 활용해야 합니다. GSI에서 제한이 발생하면 기본 테이블의 쓰기 작업에 역압이 가해지기 때문입니다.