CertNote/ 출퇴근 학습 노트
로드맵
KOEN
CLF-C02 · FoundationalCloud Practitioner - Foundational
DVA-C02 · AssociateDeveloper - Associate
  • Week 1
    • 1.개발자 시점에서 본 AWS: 리전, 인프라, 그리고 책임의 경계
    • 2.IAM의 4대 엔터티: User, Group, Role, Policy
    • 3.STS와 정책 조건: 임시 자격증명의 깊은 세계
    • 4.AWS CLI와 SDK: 자격증명 체이닝부터 SigV4까지
    • 5.Week 1 종합: 인프라와 IAM이 만드는 신뢰의 사슬
  • Week 2
  • Week 3
  • Week 4
  • Week 5
  • Week 6
    • 1.DynamoDB: NoSQL의 철학과 파티션 설계의 수학
    • 2.DynamoDB: 파티션 키 설계의 수학, LSI/GSI 내부 동작, Single-Table Design
    • 3.DynamoDB: RCU/WCU 수학, DAX 아키텍처, Streams 처리
    • 4.DynamoDB: 트랜잭션, 조건부 쓰기, TTL의 내부 동작
    • 5.Week 6 종합 복습: DynamoDB 전체 지형도
  • Week 7
  • Week 8
  • Week 9
  • Week 10
  • Week 11
  • Week 12
  • Week 13
SAA-C03 · AssociateSolutions Architect - Associate
SOA-C02 · AssociateCloudOps Engineer - Associate
SAP-C02 · ProfessionalSolutions Architect - Professional
DOP-C02 · ProfessionalDevOps Engineer - Professional
SCS-C03 · SpecialtySecurity - Specialty
MLA-C01 · AssociateMachine Learning Engineer - Associate
AIF-C01 · FoundationalAI Practitioner - Foundational
DEA-C01 · AssociateData Engineer - Associate
MLS-C01 · SpecialtyMachine Learning - Specialty
합격 후기

© CertNote · 주간랩스

  • 소개
  • 수정 기록
  • 문의
  • 이용약관
  • 개인정보처리방침
← DVA-C02/Week 6/Day 1

기준: DVA-C02 시험 가이드·오류 제보

DVA-C02· AssociateWeek 6 · Day 1읽기 약 16분

Day 1 - DynamoDB: NoSQL의 철학과 파티션 설계의 수학

관계형 데이터베이스를 오래 써온 개발자가 DynamoDB를 처음 배울 때 가장 충격을 받는 부분은 두 가지다. 첫째, JOIN이 없다. 둘째, 어떻게 데이터를 조회할지를 먼저 결정한 다음 테이블을 설계해야 한다 — RDBMS와는 정반대 순서다. 이 day에서는 왜 Amazon이 2007년 DynamoDB의 전신인 Dynamo를 만들었는지, 그 핵심 아이디어인 파티셔닝과 일관성 모델이 어떻게 동작하는지를 이해한다. 이 원리를 이해하면 DVA-C02의 DynamoDB 문제는 외우지 않아도 풀린다.

Dynamo 논문의 배경 — 2007년 Amazon의 고민

2007년 10월, Amazon의 수석 엔지니어들이 ACM SOSP 학술회의에서 "Dynamo: Amazon's Highly Available Key-value Store"라는 논문을 발표했다. 이 논문은 분산 시스템 역사에서 가장 영향력 있는 논문 중 하나가 됐다.

당시 Amazon의 문제는 이랬다. MySQL 같은 관계형 DB는 트랜잭션을 위해 락(lock)을 사용하고, 분산 확장이 어려우며, 특히 피크 트래픽(블랙 프라이데이, 크리스마스)에서 수십만 TPS를 처리하기 어렵다. Amazon 내부 서비스 대부분이 기본 키 조회로 충분하고 복잡한 JOIN이 거의 필요하지 않다는 분석이 있었다. 그렇다면 JOIN을 포기하고 수평 확장에 최적화된 스토리지를 만들면 어떨까?

Dynamo 논문은 일관적인 해싱(Consistent Hashing), 벡터 클록(Vector Clock), 가십 프로토콜(Gossip Protocol), 최종 일관성(Eventual Consistency) 같은 분산 시스템 개념을 조합한 Key-Value 스토리지를 설계했다. 이것이 DynamoDB의 이론적 토대다.

CAP 정리에 따르면 분산 시스템은 일관성(Consistency), 가용성(Availability), 파티션 내성(Partition Tolerance) 중 두 개만 보장할 수 있다. Amazon의 Dynamo는 AP(가용성 + 파티션 내성)를 선택하고 일관성을 희생해 "eventual consistency"를 채택했다. DynamoDB는 이 기반 위에서 선택적으로 Strong Consistency를 추가 제공한다.

DynamoDB vs RDBMS — 패러다임의 차이

개념RDBMSDynamoDB
저장 단위행(Row)항목(Item)
조직 단위테이블, 스키마테이블, 파티션
스키마고정 (DDL 필수)유연 (PK 외 자유)
쿼리 방식SQL, 임의 컬럼 검색PK 기반만 효율적
확장 방식수직 확장(더 큰 서버)수평 확장(파티션 추가)
트랜잭션기본 ACIDTransactWrite/Get (2x 비용)
JOIN자유롭게없음 (애플리케이션 레벨)
인덱스자유롭게 생성LSI(5개), GSI(20개) 제한
확장 한도TB 수준(단일 서버)PB 수준(자동 파티셔닝)

RDBMS는 "데이터를 어떻게 저장할까"를 먼저 생각하고, 나중에 다양한 쿼리로 데이터를 뽑는다. DynamoDB는 반대다 — "어떻게 조회할까"를 먼저 결정하고 그에 맞춰 PK와 인덱스를 설계한다. 이 패러다임 전환이 DynamoDB 학습의 첫 번째 관문이다.

키-값 패턴(검색 결과 캐싱, 사용자별 선호 저장)에서 RDBMS의 락 경합이 병목이 되면 DynamoDB로 옮기는 선택이 있다. 반면 검색 필터와 정렬 같은 복잡한 쿼리는 DynamoDB의 한계가 있어 Elasticsearch 같은 별도 검색 엔진을 함께 쓴다. DynamoDB의 한계를 알고 적재적소에 쓰는 것이 요점이다.

파티셔닝 메커니즘 — SHA-256 해시와 파티션 결정

DynamoDB가 PK 값을 받으면 내부적으로 SHA-256 해시를 계산하고, 해시 값으로 데이터가 저장될 파티션을 결정한다. 같은 PK 값은 항상 같은 파티션에 저장된다.

파티션 키 → SHA-256 해시 → 해시 공간에서 파티션 결정
                           → 해당 파티션 노드에 저장

예시:
"user001" → hash(user001) = 0x7a3f... → 파티션 5
"user002" → hash(user002) = 0x1b2c... → 파티션 2
"user003" → hash(user003) = 0x9d4a... → 파티션 5  (우연히 같은 파티션)

파티션 하나의 용량 한도:

  • 스토리지: 파티션이 가득 차면 DynamoDB가 자동으로 파티션을 추가 할당한다
  • 처리량: 최대 3,000 RCU + 1,000 WCU

파티션이 가득 차거나 프로비저닝한 처리량이 기존 파티션이 감당할 수 있는 범위를 넘으면 DynamoDB가 파티션을 추가 할당한다. 파티션 관리는 백그라운드에서 자동으로 이루어지며 애플리케이션에는 투명하다.

DynamoDB의 파티셔닝은 일관적 해싱(Consistent Hashing)의 변형을 사용한다. 일관적 해싱의 핵심 특성은 노드(파티션)가 추가/제거될 때 재배치되는 데이터의 양이 최소화된다는 것이다. 일반 해시(key % N)는 N이 변할 때 거의 모든 데이터를 재배치해야 하지만, 일관적 해싱은 1/N의 데이터만 이동한다. DynamoDB가 PB 규모에서도 파티션 추가를 원활하게 처리할 수 있는 이유다.

핫 파티션 문제 — 잘못된 PK 설계의 대가

DynamoDB 설계에서 흔히 하는 실수가 낮은 카디널리티(cardinality) 값을 파티션 키로 사용하는 것이다. 카디널리티란 고유 값의 수다.

나쁜 PK 예시들:
  status: "PENDING"/"COMPLETED"/"FAILED"     → 3가지 파티션만 존재
  country: "KR"/"US"/"JP"                   → 일부 국가에 요청이 쏠리면 그 파티션만 뜨거워짐
  date: "2026-06-26"                         → 오늘 모든 쓰기가 한 파티션에 집중
  boolean: true/false                         → 2가지 파티션만

좋은 PK 예시들:
  userId: UUID                               → 수백만 고유 값
  orderId: UUID                              → 수백만 고유 값
  deviceId: 디바이스 시리얼번호              → 균등 분산

날짜를 PK로 사용하는 패턴이 특히 위험하다. 오늘 날짜("2026-06-26")를 PK로 쓰면 오늘의 모든 쓰기가 하나의 파티션에 집중된다. 이 파티션은 1,000 WCU 한도를 초과하면 ProvisionedThroughputExceededException이 발생한다.

안티패턴문제개선 방법
PK = 날짜오늘 쓰기가 한 파티션 집중PK = 날짜#샤드번호 (예: 2026-06-26#3)
PK = status 코드3~5개 파티션만 존재PK = userId, GSI PK = status
PK = sequential ID순차 ID는 해시 후에도 치우침 가능PK = UUID
PK = category인기 카테고리에 집중PK = category#uuid

⚠️ 함정: "DynamoDB가 Adaptive Capacity로 핫 파티션을 자동 처리한다"고 알고 있는 수험생이 많다. Adaptive Capacity는 다른 파티션의 여유 용량을 핫 파티션에 재분배하는 기능이다. 하지만 이것은 임시 완충제일 뿐이다. 테이블 전체 WCU를 초과하면 Adaptive Capacity도 도움이 안 된다. 근본 해결책은 항상 PK 설계다.

DynamoDB의 데이터 유형 전체

DynamoDB는 세 범주의 데이터 유형을 지원한다.

스칼라(Scalar) 유형: 단일 값

  • S - String: "hello", "2026-06-26T00:00:00Z" (날짜는 ISO 8601 문자열로 저장)
  • N - Number: 42, 3.14, 1234567890123 (정수, 소수, 큰 수 모두)
  • B - Binary: Base64 인코딩 바이너리 데이터 (이미지 썸네일, 직렬화된 데이터)
  • BOOL - Boolean: true, false
  • NULL - Null: true (값이 없음을 명시적으로 표현)

집합(Set) 유형: 같은 타입의 중복 없는 집합

  • SS - String Set: {"apple", "banana", "cherry"}
  • NS - Number Set: {1, 2, 3, 4, 5}
  • BS - Binary Set: 바이너리 집합

문서(Document) 유형: 중첩 구조

  • M - Map: {"key1": {"S": "value"}, "key2": {"N": "42"}} — 중첩 JSON 객체
  • L - List: [{"S": "hello"}, {"N": "42"}, {"BOOL": true}] — 혼합 타입 배열

항목 최대 크기는 400KB다. 이미지, 동영상 같은 큰 데이터는 S3에 저장하고 DynamoDB에는 S3 URL 또는 키만 저장하는 것이 표준 패턴이다.

DynamoDB의 Map(M) 타입은 JSON과 개념적으로 동일하다. 사실 DynamoDB의 데이터 모델은 JSON을 이진 형식으로 인코딩한 것이다(내부적으로 CBOR과 유사한 형식). aws dynamodb get-item --output json을 실행하면 DynamoDB가 반환하는 응답이 타입 어노테이션이 포함된 JSON임을 볼 수 있다. Map 타입의 중첩 깊이에는 이론적 제한이 없지만, 전체 항목 크기 400KB 안에 들어야 한다.

읽기 일관성 모델 — 분산 시스템의 트레이드오프

DynamoDB는 데이터를 최소 3개의 AZ에 걸쳐 동기적으로 복제한다. 쓰기가 완료됐다는 응답은 3개 AZ 중 최소 2개(quorum)에 쓰기가 성공했을 때 돌아온다.

이 분산 복제 때문에 읽기 시점에 따라 최신 데이터를 보장할 수 없는 상황이 생긴다.

최종 일관성 읽기(Eventually Consistent Read): DynamoDB가 임의의 노드 중 하나에서 읽는다. 방금 쓴 데이터가 아직 다른 노드에 전파되지 않았다면 이전 버전 데이터를 반환할 수 있다. 소비: 4KB당 0.5 RCU. 기본값.

강력한 일관성 읽기(Strongly Consistent Read): DynamoDB가 최신 데이터를 보장하는 "주 노드(leader)"에서 읽는다. 항상 최신 쓰기 후의 데이터를 반환한다. 소비: 4KB당 1 RCU (최종 일관성의 2배). ConsistentRead: true 파라미터 필요.

트랜잭션 읽기(Transactional Read): 여러 항목을 원자적으로 읽는다. 소비: 4KB당 2 RCU. TransactGetItems API 사용.

읽기 유형비용최신 데이터 보장GSI 지원
Eventually Consistent0.5 RCU/4KB❌ (거의 항상 최신)✅
Strongly Consistent1 RCU/4KB✅❌ (기본 테이블 + LSI만)
Transactional2 RCU/4KB✅❌

⚠️ 함정: GSI는 강력한 일관성 읽기를 지원하지 않는다. 항상 최종 일관성만 가능하다. 이는 GSI가 비동기적으로 복제되기 때문이다 — 기본 테이블에 쓰기가 완료돼도 GSI에 반영되기까지 짧은 지연이 있다. 강력한 일관성이 필요하면 기본 테이블이나 LSI를 사용해야 한다.

DynamoDB 표현식 시스템 — 5가지 표현식의 역할

DynamoDB는 조건, 업데이트, 필터를 SQL 대신 표현식(Expression)으로 처리한다. 5가지 표현식을 혼동하지 않는 것이 중요하다.

import boto3
 
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Orders')
 
# 1. KeyConditionExpression — Query에서 파티션 키(필수) + 정렬 키(선택) 조건
response = table.query(
    KeyConditionExpression=Key('userId').eq('U001') & 
                           Key('orderDate').between('2026-01-01', '2026-06-30')
)
 
# 2. FilterExpression — 읽은 후 클라이언트 측 필터링 (RCU는 그대로 소비!)
response = table.query(
    KeyConditionExpression=Key('userId').eq('U001'),
    FilterExpression=Attr('status').eq('COMPLETED')  # RCU 절감 없음
)
 
# 3. UpdateExpression — 항목 속성 수정
table.update_item(
    Key={'userId': 'U001', 'orderDate': '2026-06-26'},
    UpdateExpression='SET #s = :status, updatedAt = :ts ADD orderCount :one',
    ExpressionAttributeNames={'#s': 'status'},   # 예약어 우회
    ExpressionAttributeValues={':status': 'SHIPPED', ':ts': '2026-06-26T10:00:00Z', ':one': 1}
)
 
# 4. ConditionExpression — 조건부 쓰기 (조건 불일치 시 ConditionalCheckFailedException)
table.put_item(
    Item={'userId': 'U001', 'email': 'kim@example.com'},
    ConditionExpression=Attr('userId').not_exists()  # 중복 방지
)
 
# 5. ProjectionExpression — 반환할 속성 선택 (네트워크 비용 절감, RCU는 전체 항목 기준)
response = table.get_item(
    Key={'userId': 'U001'},
    ProjectionExpression='email, #n',
    ExpressionAttributeNames={'#n': 'name'}
)

FilterExpression은 항목을 읽은 후에 필터링한다. 즉, DynamoDB는 먼저 파티션 키 조건에 맞는 모든 항목을 읽고(RCU 소비), 그 다음 FilterExpression을 적용해서 일부를 제거한다. 결과 항목이 10개여도 읽은 항목이 1,000개면 1,000개 기준으로 RCU가 청구된다. RCU를 절감하려면 FilterExpression이 아니라 GSI를 설계해 KeyConditionExpression으로 검색해야 한다.

Adaptive Capacity와 Burst Capacity

두 기능 모두 단기 처리량 초과를 처리하지만 방식이 다르다.

Burst Capacity: 미사용된 RCU/WCU를 최대 5분치 누적했다가 갑작스러운 트래픽 급증 시 사용. 자동 동작, 설정 불필요.

Adaptive Capacity: 테이블 내 한 파티션이 핫 파티션이 됐을 때, 다른 파티션의 여유 용량을 핫 파티션으로 재분배. 2018년부터 "즉시(instant)" 방식으로 개선 — 이전에는 수 분이 걸렸다.

둘 다 임시 완충제이며, 근본 해결은 설계다:

  • Burst: 짧은 피크는 처리하지만 지속적 초과는 throttling
  • Adaptive Capacity: 핫 파티션은 완화하지만 전체 테이블 처리량 한도 초과는 처리 불가

DynamoDB Local — 로컬 개발 환경

DynamoDB Local은 Java로 작성된 DynamoDB 에뮬레이터로, Docker나 JAR 파일로 로컬에서 실행할 수 있다. 실제 AWS 계정 없이 DynamoDB를 개발하고 통합 테스트할 수 있다.

# Docker로 DynamoDB Local 실행
docker run -p 8000:8000 amazon/dynamodb-local
 
# SDK를 로컬 엔드포인트로 연결
import boto3
dynamodb = boto3.resource(
    'dynamodb',
    endpoint_url='http://localhost:8000',
    region_name='us-east-1',
    aws_access_key_id='dummy',
    aws_secret_access_key='dummy'
)

주의: DynamoDB Local은 실제 DynamoDB와 동일하지 않다. 성능 특성, 처리량 제한, 일부 신규 기능은 시뮬레이션되지 않는다. 통합 테스트에는 적합하지만 성능 테스트에는 실제 DynamoDB를 사용해야 한다.

오늘 살펴본 DynamoDB의 철학 — 파티션 해싱, 일관성 모델, 표현식 시스템 — 은 나머지 DynamoDB 주제 전반의 기반이다. 다음 day에서는 이 기반 위에서 LSI/GSI를 어떻게 설계하고, 단일 테이블 설계(Single-Table Design) 패턴이 왜 DynamoDB의 표준이 됐는지를 살펴본다.

📝 연습 문제

선택지를 클릭하면 정답·해설이 펼쳐집니다.

문제 1

DynamoDB 테이블에서 최종 일관성 읽기와 강력한 일관성 읽기의 RCU 소비는?

문제 2

DynamoDB에서 GSI를 사용할 때 강력한 일관성 읽기를 요청하면 어떻게 되는가?

문제 3

DynamoDB FilterExpression에 대한 올바른 설명은?

문제 4

다음 중 DynamoDB에서 핫 파티션이 발생할 가능성이 가장 높은 파티션 키 설계는?

문제 5

DynamoDB 항목의 최대 크기와, 이 제한을 우회하기 위한 표준 패턴은?

문제 6

전자상거래 플랫폼에서 DynamoDB의 주문 테이블에 userId를 파티션 키로, orderId를 정렬 키로 사용하고 있다. 특정 userId의 최근 10개 주문을 가져오는 가장 효율적인 방법은?

문제 7

DynamoDB의 Adaptive Capacity와 Burst Capacity의 차이는?

이전S3 고급 기능 + Week 5 종합 복습Week 5 · Day 5다음 DynamoDB: 파티션 키 설계의 수학, LSI/GSI 내부 동작, Single-Table DesignWeek 6 · Day 2

참고 공식 자료

  • DVA-C02 공식 시험 안내(새 탭에서 열림)
  • Amazon DynamoDB 공식 문서(새 탭에서 열림)
  • Amazon S3 공식 문서(새 탭에서 열림)

이 페이지

  • Dynamo 논문의 배경 — 2007년 Amazon의 고민
  • DynamoDB vs RDBMS — 패러다임의 차이
  • 파티셔닝 메커니즘 — SHA-256 해시와 파티션 결정
  • 핫 파티션 문제 — 잘못된 PK 설계의 대가
  • DynamoDB의 데이터 유형 전체
  • 읽기 일관성 모델 — 분산 시스템의 트레이드오프
  • DynamoDB 표현식 시스템 — 5가지 표현식의 역할
  • Adaptive Capacity와 Burst Capacity
  • DynamoDB Local — 로컬 개발 환경
  • 연습 문제