1. NoSQL vs SQL
데이터베이스는 크게 SQL(관계형) 과 NoSQL(비관계형) 두 가지로 나뉩니다. MySQL, PostgreSQL 같은 전통적인 데이터베이스가 SQL이고, DynamoDB, MongoDB 같은 것이 NoSQL입니다. 어떤 것이 더 좋다기보다는 용도에 따라 선택하는 것이 중요합니다.
전통적 아키텍처 (RDBMS)
| 특징 | 설명 |
|---|---|
| 쿼리 언어 | SQL |
| 데이터 모델링 | 엄격한 스키마 |
| 기능 | JOIN, 집계, 복잡한 계산 |
| 스케일링 | 수직 (CPU/RAM) + 수평 (Read Replica) |
수직 스케일링이란 서버 한 대의 CPU, RAM을 업그레이드하는 것이고, 수평 스케일링은 서버 여러 대를 추가하는 것입니다.
NoSQL 특징
| 특징 | 설명 |
|---|---|
| 분산 | 분산 데이터베이스 |
| JOIN | 지원 안 함 (또는 제한적) |
| 집계 | SUM, AVG 등 미지원 |
| 스케일링 | 수평 |
| 데이터 구조 | 하나의 행에 쿼리 필요 데이터 모두 포함 |
쉽게 말해: SQL은 엑셀 시트처럼 정해진 열(컬럼)이 있고, 여러 시트를 JOIN으로 연결합니다. NoSQL은 JSON처럼 유연한 구조로, 필요한 데이터를 한 곳에 모아둡니다.
💡 NoSQL vs SQL은 옳고 그름이 아님 → 데이터 모델링 방식이 다를 뿐
2. DynamoDB 개요
DynamoDB는 AWS에서 제공하는 완전 관리형 NoSQL 데이터베이스입니다. "완전 관리형"이란 서버 설치, 패치, 백업 등을 AWS가 알아서 해준다는 의미입니다. 개발자는 데이터 저장과 조회에만 집중하면 됩니다.
특징
| 항목 | 설명 |
|---|---|
| 유형 | 완전 관리형 NoSQL |
| 가용성 | Multi-AZ 복제 |
| 규모 | 초당 수백만 요청, 수조 행, 수백 TB |
| 성능 | 빠르고 일관된 저지연 |
| 보안 | IAM 통합 |
| 이벤트 | DynamoDB Streams |
| 비용 | 저렴, Auto-scaling |
| Table Class | Standard, Infrequent Access (IA) |
Multi-AZ란 여러 가용 영역(데이터센터)에 데이터를 복제해서 하나가 장애가 나도 서비스가 계속되는 것입니다. IA(Infrequent Access) 는 자주 접근하지 않는 데이터를 저렴하게 저장하는 옵션입니다.
기본 구조
DynamoDB
│
└─ Table
│
├─ Item (행) - 최대 400KB
│ │
│ ├─ Attribute (열)
│ ├─ Attribute
│ └─ Attribute
│
└─ Item
└─ ...쉽게 이해하기: Table은 엑셀 파일, Item은 한 행(row), Attribute는 각 열(column)의 값입니다. 단, DynamoDB는 각 Item마다 다른 Attribute를 가질 수 있어서 유연합니다.
데이터 타입
| 카테고리 | 타입 |
|---|---|
| Scalar | String, Number, Binary, Boolean, Null |
| Document | List, Map |
| Set | String Set, Number Set, Binary Set |
Scalar는 단일 값(문자열, 숫자 등), Document는 중첩 구조(JSON의 배열이나 객체), Set은 중복 없는 값들의 집합입니다.
3. Primary Key
Primary Key는 테이블에서 각 아이템을 고유하게 식별하는 키입니다. DynamoDB에서는 두 가지 방식으로 Primary Key를 구성할 수 있습니다.
Option 1: Partition Key (HASH)
┌────────────────────────────────────────────────────┐
│ User_ID (PK) │ First_Name │ Last_Name │ Age │
├────────────────┼──────────────┼─────────────┼─────┤
│ 7791a3d6-... │ John │ William │ 46 │
│ 873e0634-... │ Katie │ Lucas │ 31 │
│ a80f73a1-... │ Oliver │ - │ 24 │
└────────────────────────────────────────────────────┘- Partition Key는 고유해야 함
- 높은 카디널리티 선택 (데이터 분산)
카디널리티(Cardinality) 란 해당 키가 가질 수 있는 고유한 값의 개수입니다. 예: 성별(남/여)은 카디널리티가 낮고, 주민등록번호는 카디널리티가 높습니다. 카디널리티가 높을수록 데이터가 골고루 분산됩니다.
Option 2: Partition Key + Sort Key (HASH + RANGE)
┌─────────────────────────────────────────────────────────────┐
│ User_ID (PK) │ Game_ID (SK) │ Score │ Result │
├────────────────┼────────────────┼─────────┼────────────────┤
│ 7791a3d6-... │ 4421 │ 92 │ Win │
│ 873e0634-... │ 4521 │ 77 │ Win │
│ 873e0634-... │ 1894 │ 14 │ Lose │
└─────────────────────────────────────────────────────────────┘
↑
같은 PK, 다른 SK (조합이 고유)- 조합이 고유해야 함
- 같은 Partition Key → 데이터 그룹화
실제 예시: 게임 앱에서 한 유저(User_ID)가 여러 게임(Game_ID)을 플레이한 기록을 저장할 때 사용합니다. User_ID로 그룹화하고, Game_ID로 정렬하면 "특정 유저의 모든 게임 기록"을 효율적으로 조회할 수 있습니다.
Partition Key 선택 가이드
영화 DB에서 최적의 Partition Key는?
❌ movie_language → 값이 적음, 영어에 편중
❌ producer_name → 카디널리티 낮음
❌ leader_actor_name → 카디널리티 중간
✅ movie_id → 가장 높은 카디널리티!4. Read/Write Capacity Modes
DynamoDB는 읽기/쓰기 용량을 관리하는 두 가지 모드를 제공합니다. 얼마나 많은 요청을 처리할 수 있는지를 결정하는 중요한 설정입니다.
모드 비교
| 항목 | Provisioned | On-Demand |
|---|---|---|
| 용량 계획 | 필요 | 불필요 |
| 스케일링 | Auto-scaling 옵션 | 자동 |
| 비용 | 저렴 | 2.5배 비쌈 |
| Throttle | 가능 | 없음 |
| 용도 | 예측 가능한 워크로드 | 예측 불가능한 워크로드 |
Provisioned: 미리 "초당 100번 읽기, 50번 쓰기"처럼 용량을 예약합니다. 예측 가능한 트래픽에 적합하고 비용이 저렴합니다.
On-Demand: 사용한 만큼만 과금됩니다. 갑자기 트래픽이 폭주해도 자동으로 처리하지만, 단가가 비쌉니다. 신규 서비스나 트래픽 예측이 어려울 때 적합합니다.
💡 모드 전환: 24시간에 한 번
5. Write Capacity Units (WCU)
WCU는 DynamoDB에서 쓰기 작업의 처리량을 측정하는 단위입니다. Provisioned 모드에서 미리 할당해야 하며, 시험에서 계산 문제가 자주 출제됩니다.
정의
- 1 WCU = 1KB 이하 아이템 1개/초 쓰기
- 1KB 초과 시 더 많은 WCU 소비
핵심 공식:
필요한 WCU = 초당 쓰기 수 × (아이템 크기 / 1KB)(크기는 올림 처리)
계산 예시
예시 1: 10개/초, 아이템 크기 2KB
10 × (2KB / 1KB) = 20 WCU예시 2: 6개/초, 아이템 크기 4.5KB
6 × (5KB / 1KB) = 30 WCU ← 4.5 → 5로 올림예시 3: 120개/분, 아이템 크기 2KB
(120/60) × (2KB / 1KB) = 4 WCU계산 팁: 항상 1) 초당 횟수로 변환 2) 아이템 크기를 1KB 단위로 올림 3) 두 값을 곱하면 됩니다.
6. Read Capacity Units (RCU)
RCU는 읽기 작업의 처리량 단위입니다. WCU와 다르게 읽기 일관성(Consistency) 에 따라 계산이 달라지므로 주의해야 합니다.
정의
- 1 RCU = 4KB 이하 아이템
- Strongly Consistent: 1개/초
- Eventually Consistent: 2개/초
- 4KB 초과 시 더 많은 RCU 소비
Strongly vs Eventually Consistent Read
| 유형 | 설명 | RCU |
|---|---|---|
| Eventually Consistent (기본) | 쓰기 직후 오래된 데이터 가능 | 1 RCU = 2개 읽기 |
| Strongly Consistent | 쓰기 직후 정확한 데이터 | 1 RCU = 1개 읽기 |
쉽게 이해하기: DynamoDB는 데이터를 여러 서버에 복제합니다. 데이터를 쓰면 모든 서버에 복제되는 데 약간의 시간이 걸립니다.
- Eventually Consistent: 복제가 완료되지 않은 서버에서 읽을 수도 있음 (약간 오래된 데이터 가능, 하지만 저렴)
- Strongly Consistent: 반드시 최신 데이터를 읽음 (비용 2배)
Application → DynamoDB
│
┌─────┼─────┐
│ │ │
Server1 Server2 Server3
│ │
write ────→ replication (지연 가능)
│ │
read ←──── read (Eventually: 오래된 데이터 가능)계산 예시
예시 1: 10 Strongly Consistent/초, 4KB
10 × (4KB / 4KB) = 10 RCU예시 2: 16 Eventually Consistent/초, 12KB
(16/2) × (12KB / 4KB) = 24 RCU예시 3: 10 Strongly Consistent/초, 6KB
10 × (8KB / 4KB) = 20 RCU ← 6 → 8로 올림7. Partitions & Throttling
DynamoDB는 데이터를 파티션(Partition) 이라는 저장 단위로 나눠서 관리합니다. 파티션을 이해하면 성능 문제(Throttling)를 예방할 수 있습니다.
Partition 내부 구조
Application
│
▼
Hash Function
│
├─→ Partition 1 (ID_13, ID_27, ...)
├─→ Partition 2 (ID_45, ID_89, ...)
└─→ Partition 3 (...)- Partition Key → 해시 함수 → 파티션 결정
- WCU/RCU는 파티션에 균등 분배
중요: 100 WCU를 할당하고 파티션이 4개면, 각 파티션은 25 WCU만 사용 가능합니다. 특정 파티션에 요청이 몰리면 문제가 발생합니다.
Throttling 원인
Throttling이란 할당된 용량을 초과해서 요청이 거부되는 현상입니다.
| 원인 | 설명 |
|---|---|
| Hot Keys | 특정 파티션 키에 읽기 집중 |
| Hot Partitions | 특정 파티션 과부하 |
| 큰 아이템 | RCU/WCU가 아이템 크기에 비례 |
Throttling 해결책
| 해결책 | 설명 |
|---|---|
| Exponential Backoff | SDK에 기본 포함 |
| 파티션 키 분산 | 높은 카디널리티 |
| DAX | RCU 문제 시 캐시 사용 |
Exponential Backoff: 요청 실패 시 1초, 2초, 4초, 8초... 처럼 대기 시간을 점점 늘려가며 재시도하는 방식입니다. AWS SDK에 기본 포함되어 있어 별도 구현이 필요 없습니다.
8. DynamoDB API - 쓰기
DynamoDB에서 데이터를 쓰는 주요 API들입니다.
PutItem
- 새 아이템 생성 또는 전체 교체 (같은 PK)
- WCU 소비
주의: 같은 Primary Key로 PutItem을 호출하면 기존 아이템이 완전히 교체됩니다. 일부 속성만 수정하려면 UpdateItem을 사용하세요.
UpdateItem
- 기존 아이템 속성 편집 또는 새 아이템 추가
- Atomic Counter: 숫자 속성 무조건 증가
Atomic Counter 예시: 조회수를 1 증가시킬 때, 여러 사용자가 동시에 호출해도 모든 증가가 정확히 반영됩니다. 동시성 문제를 걱정할 필요 없습니다.
Conditional Writes (조건부 쓰기)
- 조건 만족 시에만 쓰기/수정/삭제
- 동시 접근 제어에 유용
- 성능 영향 없음
- 적용 대상: PutItem, UpdateItem, DeleteItem, BatchWriteItem
조건 표현식 종류:
| 표현식 | 용도 | 예시 |
|---|---|---|
| attribute_exists | 속성이 존재하는지 확인 | 별점 1개 리뷰가 있는 제품만 삭제 |
| attribute_not_exists | 속성이 존재하지 않는지 확인 | 가격 없는 항목만 삭제 |
| attribute_type | 속성 타입 확인 | 올바른 데이터 타입인지 검증 |
| contains | 문자열 포함 여부 | 특정 키워드 포함 확인 |
| begins_with | 문자열 시작 여부 | URL이 "http://"로 시작하는지 |
| IN | 값이 목록에 포함되는지 | ProductCategory가 cat1 또는 cat2인지 |
| BETWEEN | 범위 내에 있는지 | 가격이 500~600 사이인지 |
| size | 문자열 길이 확인 | 설명 길이 제한 |
💡 FilterExpression vs ConditionExpression
- FilterExpression: 읽기(Query/Scan) 결과 필터링
- ConditionExpression: 쓰기 작업 성공/실패 결정
조건부 쓰기 예시
1. UpdateItem - 가격이 한계 초과 시에만 할인 적용:
# 조건: 가격 > 500일 때만 150 할인 적용
aws dynamodb update-item \
--table-name ProductCatalog \
--key '{"id": {"N": "456"}}' \
--update-expression "SET Price = Price - :discount" \
--condition-expression "Price > :limit" \
--expression-attribute-values file://values.json
# values.json
{
":discount": {"N": "150"},
":limit": {"N": "500"}
}
# 결과:
# 가격 650 → 500 (조건 충족, 업데이트 성공)
# 가격 500 → 변경 없음 (조건 불충족, 업데이트 실패)2. DeleteItem - 가격 속성이 없는 항목 삭제:
# 가격이 없는 불완전한 항목 정리
aws dynamodb delete-item \
--table-name ProductCatalog \
--key '{"id": {"N": "789"}}' \
--condition-expression "attribute_not_exists(Price)"3. DeleteItem - 별점 1개 리뷰가 있는 제품 삭제:
# 별점 1개 리뷰가 존재하는 제품만 삭제
aws dynamodb delete-item \
--table-name ProductCatalog \
--key '{"id": {"N": "123"}}' \
--condition-expression "attribute_exists(ProductReview.OneStar)"데이터 덮어쓰기 방지 패턴
기존 항목이 있으면 쓰기 실패하도록 설정:
# Partition Key만 있는 경우
--condition-expression "attribute_not_exists(pk)"
# Partition Key + Sort Key 조합인 경우
--condition-expression "attribute_not_exists(pk) AND attribute_not_exists(sk)"💡 중요:
attribute_not_exists(partition_key)를 사용하면 해당 키의 항목이 이미 존재할 경우 조건이 거짓이 되어 덮어쓰기를 방지합니다.
복합 조건 예시
카테고리 또는 가격 범위 조건:
# ProductCategory가 cat1/cat2이거나 가격이 500~600 사이일 때 삭제
aws dynamodb delete-item \
--table-name ProductCatalog \
--key '{"id": {"N": "456"}}' \
--condition-expression "ProductCategory IN (:cat1, :cat2) OR Price BETWEEN :lo AND :hi" \
--expression-attribute-values file://values.json
# values.json
{
":cat1": {"S": "Electronics"},
":cat2": {"S": "Books"},
":lo": {"N": "500"},
":hi": {"N": "600"}
}
# 예시: ProductCategory=Electronics, Price=650
# → 첫 번째 조건(IN) 통과, 삭제 실행
# 예시: ProductCategory=Toys, Price=650
# → 두 조건 모두 불충족, 삭제 안 됨문자열 비교 (begins_with):
# 안전하지 않은 URL(http://)로 시작하는 이미지 삭제
aws dynamodb delete-item \
--table-name ProductCatalog \
--key '{"id": {"N": "123"}}' \
--condition-expression "begins_with(ImageUrl, :prefix)" \
--expression-attribute-values '{":prefix": {"S": "http://"}}'9. DynamoDB API - 읽기
DynamoDB에서 데이터를 읽는 세 가지 방법입니다. 효율성과 비용이 크게 다르므로 적절한 방법을 선택해야 합니다.
GetItem
| 항목 | 설명 |
|---|---|
| 키 조건 | Primary Key (HASH 또는 HASH+RANGE) |
| 읽기 모드 | Eventually Consistent (기본) / Strongly Consistent (옵션) |
| 속성 필터 | ProjectionExpression으로 특정 속성만 조회 |
- Primary Key로 읽기 (HASH 또는 HASH+RANGE)
- Eventually Consistent (기본), Strongly Consistent (옵션)
ProjectionExpression: 특정 속성만 조회
가장 효율적인 읽기: 정확한 Primary Key를 알 때 사용합니다. 단일 아이템을 직접 가져오므로 가장 빠르고 저렴합니다.
읽기 모드 선택:
| 모드 | RCU 소비 | 지연 시간 | 일관성 |
|---|---|---|---|
| Eventually Consistent | 기본 | 낮음 | 최신 데이터 아닐 수 있음 |
| Strongly Consistent | 2배 | 높음 | 항상 최신 데이터 |
Query
| 항목 | 설명 |
|---|---|
| KeyConditionExpression | PK (필수, =), SK (선택, =, <, >, Between, Begins with) |
| FilterExpression | 비키 속성 필터링 (결과 반환 전) |
| 반환 | Limit 또는 최대 1MB |
| 대상 | Table, LSI, GSI |
KeyConditionExpression 상세:
# Partition Key: 반드시 = (등호) 연산자만 사용 가능
partition_key = "value"
# Sort Key: 다양한 연산자 사용 가능 (선택)
sort_key = "value" # 정확히 일치
sort_key < "value" # 미만
sort_key > "value" # 초과
sort_key BETWEEN a AND b # 범위
sort_key begins_with("prefix") # 접두사FilterExpression의 특징:
- Query 작업이 완료된 후, 데이터가 반환되기 전에 필터링
- 비키(non-key) 속성에만 사용 가능 (HASH, RANGE 속성에는 사용 불가)
- RCU는 필터링 전 데이터 기준으로 소비됨
Query 예시: "user_id가 123인 사용자의 2024년 1월 이후 주문들"처럼 특정 파티션 내에서 조건에 맞는 아이템들을 효율적으로 가져옵니다.
Query 반환 제한:
# 반환 조건 (둘 중 하나 먼저 도달 시)
1. Limit 매개변수에 지정한 항목 수
2. 최대 1MB 데이터 용량
# 더 많은 데이터 필요 시
→ 페이지네이션으로 추가 요청Scan
- 전체 테이블 스캔 → 비효율적
- RCU 많이 소비
- 페이지네이션 사용 (최대 1MB)
- Parallel Scan: 빠르지만 RCU 더 소비
💡 Query > Scan (가능하면 Query 사용)
왜 Scan이 비효율적인가?: Scan은 테이블의 모든 아이템을 읽은 후 조건에 맞는 것만 반환합니다. 100만 개 중 10개만 필요해도 100만 개를 모두 읽어야 하므로 RCU를 많이 소비합니다.
Scan의 특징:
| 항목 | 설명 |
|---|---|
| 범위 | 테이블 전체 읽기 |
| 필터링 | 클라이언트 측에서만 가능 (비효율적) |
| 반환 | 최대 1MB, 페이지네이션 필요 |
| RCU | 대량 소비 |
정상 작업에 영향 주지 않으려면:
# 방법 1: Limit 적용
Scan에 Limit 문 적용 → 결과 크기 제한 → 잠시 중지 후 재개
# 방법 2: 병렬 스캔 (Parallel Scan)
여러 작업자가 동시에 데이터 세그먼트를 스캔
→ 처리량과 RCU 증가
→ 빠른 Scan 완료
→ Limit 등 조건으로 영향 제한 가능Scan과 함께 사용 가능한 표현식:
| 표현식 | 용도 |
|---|---|
| ProjectionExpression | 특정 속성만 가져오기 |
| FilterExpression | 클라이언트 측 필터링 (RCU 절약 안 됨) |
읽기 API 비교 요약
| API | 용도 | 효율성 | RCU |
|---|---|---|---|
| GetItem | 단일 아이템 (PK 지정) | ⭐⭐⭐ 최고 | 최소 |
| Query | 특정 파티션 내 여러 아이템 | ⭐⭐ 좋음 | 중간 |
| Scan | 전체 테이블 | ⭐ 비효율 | 최대 |
10. DynamoDB API - 삭제
데이터를 삭제하는 두 가지 방법입니다.
DeleteItem
- 개별 아이템 삭제
- Conditional Delete 가능
DeleteTable
- 테이블 전체 삭제
- 모든 아이템 DeleteItem보다 훨씬 빠름
팁: 테이블의 모든 데이터를 지우고 싶다면, 아이템을 하나씩 삭제하지 말고 테이블 자체를 삭제 후 재생성하세요. 훨씬 빠르고 비용도 절약됩니다.
11. Batch Operations
여러 아이템을 한 번에 처리하는 API입니다. 네트워크 왕복 횟수를 줄여 성능을 향상시킵니다.
BatchWriteItem
| 항목 | 값 |
|---|---|
| 최대 | 25개 PutItem/DeleteItem |
| 데이터 | 최대 16MB, 아이템당 400KB |
| 제한 | UpdateItem 불가 |
| 실패 | UnprocessedItems → Exponential Backoff |
BatchGetItem
| 항목 | 값 |
|---|---|
| 최대 | 100개 아이템 |
| 데이터 | 최대 16MB |
| 처리 | 병렬로 조회 (지연 최소화) |
| 실패 | UnprocessedKeys → Exponential Backoff |
UnprocessedItems/UnprocessedKeys: Batch 작업 중 일부가 실패하면 이 필드에 실패한 항목들이 담겨 반환됩니다. 이 항목들을 Exponential Backoff로 재시도해야 합니다.
12. PartiQL
DynamoDB의 독자적인 API 대신 익숙한 SQL 문법으로 데이터를 조작할 수 있게 해주는 쿼리 언어입니다.
개요
- SQL 호환 쿼리 언어
- SELECT, INSERT, UPDATE, DELETE 지원
- 여러 테이블 쿼리 가능
- Batch 작업 지원
사용 환경
- AWS Console
- NoSQL Workbench
- DynamoDB APIs
- AWS CLI / SDK
SELECT * FROM Users WHERE User_ID = '7791a3d6-...'주의: PartiQL은 내부적으로 DynamoDB API로 변환됩니다. SQL처럼 보이지만 JOIN은 지원되지 않으며, DynamoDB의 제약(Primary Key 필요 등)은 그대로 적용됩니다.
13. Local Secondary Index (LSI)
인덱스는 다른 방식으로 데이터를 조회할 수 있게 해주는 기능입니다. LSI는 같은 Partition Key 내에서 다른 속성으로 정렬해서 조회하고 싶을 때 사용합니다.
개요
| 항목 | 설명 |
|---|---|
| 목적 | 대체 Sort Key 제공 (Partition Key는 동일) |
| 구성 | 하나의 스칼라 속성 (String, Number, Binary) |
| 최대 개수 | 테이블당 5개 |
| 생성 시점 | ⚠️ 테이블 생성 시에만 정의 가능 |
┌─────────────────────────────────────────────────────────────────────────┐
│ User_ID (PK) │ Game_ID (SK) │ Score │ Game_TS (LSI) │
├────────────────┼────────────────┼─────────┼───────────────────────────┤
│ 7791a3d6-... │ 4421 │ 92 │ 2021-03-15T17:43:08 │
│ 873e0634-... │ 1894 │ 77 │ 2021-02-11T04:11:31 │
└─────────────────────────────────────────────────────────────────────────┘
↑
Alternative Sort KeyLSI가 필요한 상황
# 기본 테이블 구성
Partition Key: User_ID
Sort Key: Game_ID
# 가능한 쿼리
✅ User_ID + Game_ID 로 쿼리 가능
# 불가능한 쿼리 (LSI 없이)
❌ User_ID + Game_TS 로 쿼리 불가
→ Scan 후 클라이언트에서 필터링 필요 (비효율적)
# LSI 생성 후
✅ User_ID + Game_TS 로 쿼리 가능
→ "2020~2021년 사이 특정 사용자가 플레이한 모든 게임" 조회 가능핵심: LSI는 동일한 Partition Key를 유지하면서 다른 Sort Key로 쿼리할 수 있게 해줍니다.
실제 예시: 게임 기록 테이블에서 기본적으로 Game_ID로 정렬되어 있지만, "특정 유저의 게임 기록을 시간순으로 보고 싶다"면 Game_TS를 Sort Key로 하는 LSI를 만들면 됩니다.
Attribute Projections
인덱스에 어떤 속성을 포함할지 결정합니다. 포함된 속성만 인덱스에서 바로 조회 가능합니다.
| 옵션 | 설명 | 용도 |
|---|---|---|
| KEYS_ONLY | 키 속성만 포함 | 용량 절약 |
| INCLUDE | 지정한 속성만 포함 | 필요한 속성만 선택 |
| ALL | 모든 속성 포함 | 완전한 쿼리 필요 시 |
14. Global Secondary Index (GSI)
GSI는 LSI보다 강력합니다. 완전히 다른 Partition Key로 데이터를 조회할 수 있습니다. 마치 같은 데이터를 다른 방식으로 정리한 별도의 테이블처럼 동작합니다.
개요
| 항목 | 설명 |
|---|---|
| 목적 | 대체 Primary Key 제공 (완전히 다른 HASH 또는 HASH+RANGE) |
| 구성 | 스칼라 속성 (String, Number, Binary) |
| 용량 | ⚠️ 별도 RCU/WCU 프로비저닝 필요 |
| 생성 시점 | 테이블 생성 후에도 추가/수정 가능 |
💡 GSI는 완전히 새로운 테이블처럼 동작합니다. 별도의 RCU/WCU가 필요하고, 프로젝션할 속성을 지정해야 합니다.
TABLE (User_ID로 쿼리) GSI (Game_ID로 쿼리)
┌────────────────────────┐ ┌────────────────────────┐
│ User_ID │ Game_ID │... │ │ Game_ID │ Game_TS │... │
├─────────┼─────────┼────┤ ├─────────┼─────────┼────┤
│ 7791... │ 4421 │ │ │ 4421 │ 2021... │ │
│ 873e... │ 1894 │ │ │ 1894 │ 2021... │ │
└────────────────────────┘ └────────────────────────┘
↑ ↑
User_ID로만 쿼리 가능 Game_ID로 쿼리 가능!GSI가 필요한 상황
# 기본 테이블 구성
Partition Key: User_ID
Sort Key: Game_ID
# 불가능한 쿼리 (GSI 없이)
❌ Game_ID로 쿼리 불가
→ "이 게임을 플레이한 모든 유저" 조회 불가
→ Scan 후 클라이언트에서 필터링 필요
# GSI 생성 후
GSI Partition Key: Game_ID
GSI Sort Key: Game_TS
Projected Attributes: User_ID
✅ Game_ID로 쿼리 가능!
→ "특정 게임을 플레이한 모든 유저와 플레이 시간" 조회 가능핵심: GSI는 완전히 다른 Partition Key를 정의해서 새로운 쿼리 패턴을 생성합니다.
실제 예시: 주문 테이블이 Order_ID로 조회되도록 설계되어 있는데, "특정 상품(Product_ID)의 모든 주문"을 조회하고 싶다면? Product_ID를 Partition Key로 하는 GSI를 만들면 됩니다.
GSI Throttling ⚠️
⚠️ 시험 빈출: GSI에서 쓰기가 Throttle되면 메인 테이블도 Throttle됩니다!
# 상황
메인 테이블 WCU: 충분함 ✅
GSI WCU: 부족함 ❌
# 결과
GSI 쓰기 Throttle 발생
↓
메인 테이블 쓰기도 Throttle! ❌대응 방안:
- GSI Partition Key를 신중하게 선택 (높은 카디널리티)
- GSI WCU를 적절하게 할당
LSI vs GSI 비교
| 항목 | LSI | GSI |
|---|---|---|
| Partition Key | 동일 | 다름 |
| Sort Key | 대체 | 대체 |
| 생성 시점 | 테이블 생성 시만 | 언제든 |
| RCU/WCU | 메인 테이블 사용 | 별도 프로비저닝 |
| Throttling | 특별 고려 없음 | 메인 테이블에 영향 |
인덱스 선택 가이드
# 언제 LSI를 사용할까?
- 동일한 Partition Key 내에서 다른 정렬 기준이 필요할 때
- 테이블 설계 시점에 쿼리 패턴을 알고 있을 때
- 예: "특정 유저의 게임 기록을 시간순으로 조회"
# 언제 GSI를 사용할까?
- 완전히 다른 Partition Key로 쿼리해야 할 때
- 테이블 생성 후 새로운 쿼리 패턴이 필요할 때
- 예: "특정 게임을 플레이한 모든 유저 조회"시험 핵심: LSI는 테이블 생성 시에만 만들 수 있고, GSI는 언제든 추가 가능합니다. GSI가 Throttle되면 메인 테이블 쓰기도 실패할 수 있으니 주의하세요!
15. Optimistic Locking
여러 클라이언트가 동시에 같은 데이터를 수정하려 할 때 데이터 충돌을 방지하는 기법입니다. "낙관적"이라는 이름은 "충돌이 거의 없을 것"이라고 가정하고, 실제 충돌 시에만 처리하기 때문입니다.
개념
- Conditional Writes를 이용한 낙관적 잠금
- 버전 번호로 충돌 감지
DynamoDB Table
User_ID: 7791...
Name: Michael
Version: 1
Client 1: UPDATE Name = 'John' WHERE Version = 1 ✅ → Version = 2
Client 2: UPDATE Name = 'Lisa' WHERE Version = 1 ❌ (Version이 이미 2)작동 원리: 각 아이템에 version 속성을 추가합니다. 수정 시 "현재 version이 내가 읽은 값과 같을 때만 수정"하고, 성공하면 version을 1 증가시킵니다. 다른 클라이언트가 먼저 수정했다면 version이 달라져서 실패합니다.
16. DynamoDB Accelerator (DAX)
DAX는 DynamoDB 전용 캐시 서비스입니다. 자주 읽는 데이터를 메모리에 저장해두어 응답 속도를 밀리초에서 마이크로초로 단축합니다.
개요
| 항목 | 설명 |
|---|---|
| 유형 | 완전 관리형, 고가용성, 무결절성 인메모리 캐시 |
| 지연 시간 | 캐시된 읽기/쿼리에 마이크로초 지연 |
| 호환성 | 기존 DynamoDB API와 완벽 호환 |
| 코드 변경 | ❌ 애플리케이션 로직 변경 불필요 |
캐시란?: 자주 사용하는 데이터를 빠른 저장소(메모리)에 임시 보관하는 것입니다. 같은 데이터 요청 시 DynamoDB까지 가지 않고 캐시에서 바로 반환합니다.
DAX가 해결하는 문제: Hot Key
# Hot Key 문제
특정 키(항목)를 너무 많이 읽음
↓
RCU 스로틀 발생!
↓
# DAX로 해결
DAX 클러스터가 인기 데이터를 캐시
↓
DynamoDB 대신 캐시에서 반환 → 스로틀 방지아키텍처
┌─────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Application │─────▶│ DAX Cluster │─────▶│ DynamoDB Table │
└─────────────┘ │ (인메모리 캐시) │ └─────────────────┘
│ │
│ ┌───────────┐ │
│ │ Node 1 │ │ ← 프로비저닝 필요
│ │ Node 2 │ │ ← 최대 10개 노드
│ │ Node 3 │ │ ← Multi-AZ 권장
│ └───────────┘ │
│ │
│ TTL: 5분 (기본)│
└─────────────────┘애플리케이션은 DAX 클러스터와 직접 상호 작용하고, DAX가 DynamoDB 테이블에서 데이터를 가져옵니다.
특징
| 항목 | 값 |
|---|---|
| 용도 | Hot Key 문제 해결 |
| TTL | 기본 5분 (모든 캐시 데이터) |
| 노드 수 | 클러스터당 최대 10개 |
| Multi-AZ | 프로덕션: 최소 3노드 권장 (AZ당 1개) |
| 보안 | 미사용 시 암호화, KMS, VPC, IAM, CloudTrail |
DAX vs ElastiCache
💡 시험 빈출: DAX를 사용해야 하는 경우 vs ElastiCache를 사용해야 하는 경우
Application
│
├─→ DAX → DynamoDB
│ (개별 객체 캐시, Query/Scan 캐시)
│ → 간단한 유형의 쿼리: 객체, 쿼리, 스캔
│
└─→ ElastiCache
(집계 결과 저장)
→ 복잡한 계산 결과: SUM, 필터링, 통계 등| 사용 사례 | DAX | ElastiCache |
|---|---|---|
| DynamoDB 개별 객체 캐시 | ✅ | ❌ |
| Query/Scan 결과 캐시 | ✅ | ❌ |
| 애플리케이션 계산 결과 저장 | ❌ | ✅ |
| SUM, 필터링 등 집계 결과 | ❌ | ✅ |
언제 무엇을 사용할까?
# DAX 사용
- DynamoDB 데이터를 그대로 캐싱
- GetItem, Query, Scan 결과 캐싱
- Hot Key 문제 해결
# ElastiCache 사용
- 애플리케이션에서 계산한 결과 저장 (통계, 랭킹, 집계 등)
- 계산 비용이 많이 드는 작업의 결과 캐싱
- DAX를 다시 쿼리하고 클라이언트에서 다시 집계하지 않아도 됨두 가지 함께 사용 가능: DynamoDB 데이터는 DAX로 캐시하고, 애플리케이션에서 계산한 복잡한 결과는 ElastiCache에 저장하는 아키텍처도 가능합니다.
17. DynamoDB Streams
DynamoDB Streams는 테이블의 변경 사항을 실시간으로 캡처하는 기능입니다. 데이터가 추가/수정/삭제될 때마다 이벤트가 발생하고, 이를 다른 서비스(Lambda 등)에서 처리할 수 있습니다.
개요
| 항목 | 설명 |
|---|---|
| 변경 유형 | 생성(Create), 수정(Update), 삭제(Delete) |
| 보존 기간 | 최대 24시간 (더 길게 보관하려면 별도 처리 필요) |
| 순서 보장 | 아이템 수준에서 순서 보장 |
| 소급 적용 | ❌ 활성화 전 데이터는 스트림에 전송 불가 |
중요: Stream 활성화 이전의 데이터는 소급해서 스트림으로 보낼 수 없습니다. 활성화 이후에 발생하는 변경만 캡처됩니다.
사용 사례
# DynamoDB Streams 활용 시나리오
1. 환영 이메일 발송
신규 사용자 생성 → Stream → Lambda → SES 이메일 발송
2. 실시간 분석
주문 데이터 변경 → Stream → Kinesis Data Analytics → 실시간 대시보드
3. 파생 테이블 생성
원본 테이블 변경 → Stream → Lambda → 다른 DynamoDB 테이블 업데이트
4. 검색 인덱싱
상품 데이터 변경 → Stream → Lambda → OpenSearch/ElasticSearch 인덱싱
5. Global Tables 복제
리전 A 변경 → Stream → 리전 B로 자동 복제 (내부적으로 Streams 사용)아키텍처
┌─────────────────┐
│ DynamoDB Table │
│ (Items 변경) │
└────────┬────────┘
│ create/update/delete
▼
┌─────────────────┐ ┌────────────────────────┐
│DynamoDB Streams │────▶│ Kinesis Data Streams │ (선택적 연동)
│ (24시간 보존) │ │ (더 긴 보존 기간 필요 시)│
└────────┬────────┘ └───────────┬────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────────┐
│ 처리 옵션 │
├─────────────────────────────────────────────────┤
│ • AWS Lambda (가장 일반적) │
│ • KCL (Kinesis Client Library) 애플리케이션 │
│ • Kinesis Data Firehose │
└─────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ 대상 서비스 │
├─────────────────────────────────────────────────┤
│ • Amazon OpenSearch (검색 인덱싱) │
│ • Amazon SNS (알림 발송) │
│ • 다른 DynamoDB Table (파생 테이블) │
│ • Amazon Redshift (데이터 웨어하우스) │
│ • Amazon S3 (아카이브 저장) │
└─────────────────────────────────────────────────┘실제 활용 예시: 주문 테이블에 새 주문이 들어오면 → Stream으로 Lambda 트리거 → 재고 테이블 업데이트 + 알림 발송. 이런 이벤트 기반 아키텍처를 쉽게 구현할 수 있습니다.
Stream Record 유형
스트림에 기록될 정보의 범위를 선택할 수 있습니다:
| 유형 | 내용 | 사용 시나리오 |
|---|---|---|
| KEYS_ONLY | 키 속성만 | 변경된 아이템 식별만 필요할 때 |
| NEW_IMAGE | 변경 후 전체 아이템 | 최신 상태만 필요할 때 |
| OLD_IMAGE | 변경 전 전체 아이템 | 삭제된 데이터 복구, 감사 |
| NEW_AND_OLD_IMAGES | 변경 전후 모두 | 변경 내용 비교, 상세 감사 로그 |
# 예시: 사용자 이름 변경 시 각 유형별 Stream 레코드
KEYS_ONLY:
{ "User_ID": "123" }
NEW_IMAGE:
{ "User_ID": "123", "Name": "John", "Email": "john@..." }
OLD_IMAGE:
{ "User_ID": "123", "Name": "Mike", "Email": "mike@..." }
NEW_AND_OLD_IMAGES:
{
"OldImage": { "User_ID": "123", "Name": "Mike", "Email": "mike@..." },
"NewImage": { "User_ID": "123", "Name": "John", "Email": "john@..." }
}Shards (샤드)
| 항목 | 설명 |
|---|---|
| 관리 방식 | AWS가 자동 관리 (프로비저닝 불필요) |
| Kinesis와 차이 | Kinesis Data Streams는 샤드 직접 프로비저닝 필요 |
| 확장 | 테이블 처리량에 따라 자동 확장 |
Kinesis Data Streams와 비교: Kinesis는 샤드 수를 직접 프로비저닝해야 하지만, DynamoDB Streams는 AWS가 자동으로 샤드를 관리합니다. 사용자는 샤드에 대해 신경 쓸 필요가 없습니다.
Lambda 연동
DynamoDB Streams와 Lambda를 연결하면 테이블 변경 시 자동으로 함수가 실행됩니다:
┌─────────────────┐ ┌─────────────────────┐ ┌─────────────────┐
│ DynamoDB Table │────▶│ DynamoDB Streams │────▶│ AWS Lambda │
│ (항목 변경) │ │ (Event Source) │ │ (처리 함수) │
└─────────────────┘ └─────────────────────┘ └─────────────────┘
│
│ Event Source Mapping
│ (Lambda가 Stream을 폴링)
▼
┌─────────────────────┐
│ 동기 호출 (Invoke) │
│ • 배치 처리 가능 │
│ • 재시도 자동 처리 │
└─────────────────────┘| 항목 | 설명 |
|---|---|
| 연결 방식 | Event Source Mapping |
| 호출 방식 | 동기(Synchronous) 호출 |
| 폴링 주체 | Lambda 서비스가 Stream을 폴링 |
| 필요 권한 | Lambda 실행 역할에 Stream 읽기 권한 필요 |
| 배치 처리 | 여러 레코드를 한 번에 처리 가능 |
| 오류 처리 | 실패 시 자동 재시도, DLQ(Dead Letter Queue) 설정 가능 |
💡 Event Source Mapping: Lambda가 직접 Stream을 폴링(polling) 하여 새 레코드를 가져오고, 이를 Lambda 함수에 전달합니다. 사용자가 별도로 폴링 로직을 구현할 필요가 없습니다.
24시간 보존 기간 한계 극복
# 24시간 이상 데이터 보존이 필요한 경우
DynamoDB Streams (24시간)
│
▼
Kinesis Data Streams (최대 365일 보존 가능)
│
├─→ Kinesis Data Firehose → S3 (영구 보관)
└─→ Lambda → 장기 분석/처리Kinesis Data Streams 연동: DynamoDB Streams의 24시간 보존 기간이 부족하다면, Kinesis Data Streams로 연동하여 더 긴 보존 기간(최대 365일)을 확보하거나, Firehose를 통해 S3에 영구 아카이브할 수 있습니다.
18. Time To Live (TTL)
TTL은 아이템에 만료 시간을 설정하여 자동으로 삭제되게 하는 기능입니다. 세션 데이터나 임시 데이터 관리에 유용합니다.
개요
- 만료 타임스탬프 후 자동 삭제
- WCU 소비 없음 (무료)
비용 절감 포인트: TTL 삭제는 WCU를 소비하지 않습니다. 오래된 데이터를 직접 DeleteItem으로 지우면 WCU 비용이 발생하지만, TTL을 사용하면 무료입니다.
특징
| 항목 | 설명 |
|---|---|
| 속성 타입 | Number (Unix Epoch 타임스탬프) |
| 삭제 시점 | 만료 후 며칠 내 |
| 만료 아이템 | 삭제 전까지 조회 가능 (필터링 필요) |
| 인덱스 | LSI, GSI에서도 삭제 |
| Streams | 삭제 작업이 Stream에 기록됨 (복구 가능) |
주의: TTL로 설정한 시간이 지나도 즉시 삭제되지 않습니다. AWS가 백그라운드에서 처리하므로 며칠 내에 삭제됩니다. 삭제 전까지는 조회될 수 있으니 필터링이 필요합니다.
사용 사례
- 현재 데이터만 유지 (저장 비용 절감)
- 규정 준수 (데이터 보존 기간)
- 세션 데이터 관리
19. DynamoDB CLI 옵션
시험에서 DynamoDB 관련 CLI 옵션이 출제될 수 있습니다. 데이터 조회 시 사용하는 주요 옵션들을 정리합니다.
Projection Expression
| 항목 | 설명 |
|---|---|
| 용도 | 가져올 속성(열) 지정 |
| 효과 | 필요한 데이터만 조회 → 데이터 전송량 감소 |
# 특정 속성만 가져오기
aws dynamodb get-item \
--table-name Users \
--key '{"User_ID": {"S": "123"}}' \
--projection-expression "Name, Email"
# Name과 Email 속성만 반환 (다른 속성은 제외)Filter Expression
| 항목 | 설명 |
|---|---|
| 용도 | 반환되는 아이템 필터링 |
| 특징 | 읽기 후 필터링 (RCU는 필터링 전 소비) |
# 특정 조건에 맞는 아이템만 반환
aws dynamodb scan \
--table-name Users \
--filter-expression "Age > :min_age" \
--expression-attribute-values '{":min_age": {"N": "30"}}'페이지네이션 옵션
DynamoDB와 S3 같은 서비스에서 대량 데이터를 다룰 때 페이지네이션이 필요합니다.
--page-size
| 항목 | 설명 |
|---|---|
| 용도 | 각 API 호출당 가져올 아이템 수 지정 |
| 효과 | 시간 초과 방지, 백그라운드에서 여러 번 API 호출 |
| 결과 | 사용자에게는 전체 결과 반환 (내부적으로 분할 요청) |
# 문제 상황: 10,000개 아이템을 한 번에 요청 → 시간 초과 발생!
# 해결: --page-size로 분할 요청
aws dynamodb scan \
--table-name LargeTable \
--page-size 100
# 내부 동작:
# - 100개씩 100번의 API 호출 (백그라운드)
# - 사용자에게는 전체 10,000개 결과 반환
# - 각 호출이 작아서 시간 초과 방지💡 --page-size는 더 많은 API 호출을 발생시키지만, 각 호출이 작아서 시간 초과를 방지합니다.
--max-items
| 항목 | 설명 |
|---|---|
| 용도 | CLI 결과에서 반환할 최대 아이템 수 |
| 효과 | 결과 제한, NextToken으로 다음 페이지 조회 |
| 결과 | 지정한 수만큼만 반환 + NextToken 제공 |
# 처음 25개만 가져오기
aws dynamodb scan \
--table-name Users \
--max-items 25
# 결과에 NextToken이 포함됨
# {
# "Items": [...],
# "NextToken": "eyJFeGNsdXNpdm..."
# }
# 다음 25개 가져오기 (--starting-token 사용)
aws dynamodb scan \
--table-name Users \
--max-items 25 \
--starting-token "eyJFeGNsdXNpdm..."--page-size vs --max-items 비교
| 옵션 | 내부 API 호출 | 사용자 결과 | 용도 |
|---|---|---|---|
| --page-size | 여러 번 (분할) | 전체 결과 | 시간 초과 방지 |
| --max-items | 필요한 만큼 | 지정한 수만큼 | 결과 제한 + 페이지네이션 |
# 예시: 10,000개 테이블
# --page-size 100
→ 100번의 API 호출 (백그라운드)
→ 10,000개 전체 결과 반환
# --max-items 100
→ 100개만 반환
→ NextToken으로 다음 100개 요청 가능💡 시험 포인트:
--page-size는 시간 초과 방지용,--max-items는 결과 제한 및 페이지네이션용으로 구분하세요.
20. DynamoDB Transactions
Transaction은 여러 작업을 하나의 단위로 묶어 모두 성공하거나 모두 실패하게 만드는 기능입니다. 은행 송금처럼 "A 계좌에서 출금 + B 계좌에 입금"이 반드시 함께 처리되어야 하는 경우에 필수입니다.
개요
| 항목 | 설명 |
|---|---|
| 범위 | 하나 이상의 테이블에서 여러 아이템에 대한 작업 |
| 원자성 | 모든 작업이 성공하거나, 모두 실패 (부분 성공 없음) |
| ACID | 원자성(Atomicity), 일관성(Consistency), 격리(Isolation), 영속성(Durability) 보장 |
ACID란?: 데이터베이스 트랜잭션의 4가지 핵심 속성입니다. DynamoDB 트랜잭션은 이 모든 속성을 보장합니다.
읽기/쓰기 모드
읽기 모드 (3가지):
| 모드 | 설명 |
|---|---|
| Eventually | 최종 일관성 읽기 (기본) |
| Strongly | 강력한 일관성 읽기 |
| Transactional | 전체 테이블에서 동시에 일관된 보기 (트랜잭션 내) |
쓰기 모드 (2가지):
| 모드 | 설명 |
|---|---|
| Standard | 전체 테이블에 걸쳐 쓰기 (일부 실패 가능) |
| Transactional | 모든 쓰기가 성공하거나 모두 실패 (부분 성공 없음) |
비용
| 항목 | 설명 |
|---|---|
| WCU/RCU | 일반 작업의 2배 소비 |
| 이유 | 백그라운드에서 Prepare + Commit 두 단계 처리 |
비용 2배인 이유: Transaction은 내부적으로 2단계로 처리됩니다. 1) Prepare: 모든 조건 확인 2) Commit: 실제 적용. 이 과정에서 용량을 2배 소비합니다.
트랜잭션 API
| API | 설명 |
|---|---|
| TransactGetItems | 트랜잭션에서 하나 이상의 GetItem 작업 |
| TransactWriteItems | 하나 이상의 PutItem, UpdateItem, DeleteItem 작업 |
금융 거래 예시
실제 금융 시스템에서 트랜잭션이 어떻게 사용되는지 살펴봅니다:
┌─────────────────────────────────────────────────────────────────┐
│ AccountBalance 테이블 │
├─────────────┬──────────┬─────────────────────────────────────────┤
│ Account_ID │ Balance │ Last_Tx_ts │
├─────────────┼──────────┼─────────────────────────────────────────┤
│ ACC-001 │ $5,000 │ 2024-01-15T10:30:00 │
│ ACC-002 │ $3,000 │ 2024-01-15T09:15:00 │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ BankTransactions 테이블 │
├──────────┬─────────────────┬──────────┬──────────┬──────────────┤
│ Tx_ID │ Tx_ts │ From_Acc │ To_Acc │ Amount │
├──────────┼─────────────────┼──────────┼──────────┼──────────────┤
│ TX-001 │ 2024-01-15... │ ACC-001 │ ACC-002 │ $500 │
└─────────────────────────────────────────────────────────────────┘트랜잭션 작업 흐름:
Application
│
│ 하나의 트랜잭션으로 처리
│
▼
┌─────────────────────────────────────────────────────────────┐
│ TransactWriteItems │
├─────────────────────────────────────────────────────────────┤
│ 1. UpdateItem (AccountBalance) │
│ → ACC-001 잔액에서 $500 차감 │
│ → ACC-002 잔액에 $500 추가 │
│ │
│ 2. PutItem (BankTransactions) │
│ → 새 거래 기록 추가 │
└─────────────────────────────────────────────────────────────┘
│
▼
결과: 두 테이블 모두 업데이트 성공 ✅
OR 모두 롤백 (실패 시) ❌💡 핵심: 트랜잭션이 두 테이블에 동시에 반영되거나 전혀 반영되지 않음. 금융 부문에서 이 수준의 보장이 매우 중요합니다.
용량 계산 (시험 중요!)
예시 1: 3 Transactional 쓰기/초, 5KB
3 × (5KB / 1KB) × 2 = 30 WCU
# 계산 과정:
# - 초당 3번 쓰기
# - 아이템 크기 5KB (1 WCU = 1KB)
# - 트랜잭션이므로 ×2예시 2: 5 Transactional 읽기/초, 5KB
5 × (8KB / 4KB) × 2 = 20 RCU
# 계산 과정:
# - 초당 5번 읽기
# - 아이템 크기 5KB → 8KB로 올림 (4KB 단위)
# - 트랜잭션이므로 ×2💡 시험 포인트: 트랜잭션은 항상 ×2 비용! 아이템 크기는 WCU(1KB), RCU(4KB) 단위로 올림 처리합니다.
사용 사례
| 사용 사례 | 설명 |
|---|---|
| 금융 거래 | 계좌 이체, 결제 처리 (잔액 차감 + 거래 기록) |
| 주문 관리 | 재고 감소 + 주문 생성을 원자적으로 처리 |
| 멀티플레이어 게임 | 아이템 교환, 점수 업데이트 |
| 예약 시스템 | 좌석/객실 예약 + 결제 동시 처리 |
일관성이 필요한 어떤 경우에도 DynamoDB 트랜잭션을 사용할 수 있습니다.
21. Session State Cache
웹 애플리케이션에서 사용자 세션 정보(로그인 상태, 장바구니 등)를 저장하는 방법입니다. DynamoDB는 서버리스 특성 덕분에 세션 저장소로 자주 사용됩니다.
DynamoDB vs 기타
| 옵션 | 비교 |
|---|---|
| ElastiCache | 인메모리, DynamoDB는 서버리스 |
| EFS | EC2 네트워크 드라이브 필요 |
| EBS/Instance Store | 로컬 캐시만 (공유 불가) |
| S3 | 높은 지연, 작은 객체 부적합 |
💡 DynamoDB: 서버리스 Key/Value 저장소로 세션 상태 저장에 적합
22. Write Sharding
특정 Partition Key에 쓰기가 집중되는 Hot Partition 문제를 해결하는 기법입니다. Partition Key에 임의의 접미사를 붙여 데이터를 분산시킵니다.
문제: Hot Partition
투표 앱에서 Candidate_ID를 PK로 사용:
- Candidate_A → Partition 1 (과부하!)
- Candidate_B → Partition 2 (과부하!)해결: Suffix 추가
┌──────────────────────────────────────────┐
│ Candidate_ID + Suffix │ Vote_ts │... │
├─────────────────────────┼───────────┼────┤
│ Candidate_A-11 │ 1631... │ │
│ Candidate_A-20 │ 1631... │ │
│ Candidate_B-17 │ 1631... │ │
│ Candidate_B-80 │ 1631... │ │
└──────────────────────────────────────────┘- Random Suffix: 무작위 숫자
- Calculated Suffix: 계산된 값 (예: 해시)
트레이드오프: Write Sharding을 사용하면 쓰기는 분산되지만, 읽을 때는 모든 접미사(예: Candidate_A-1 ~ Candidate_A-100)를 조회해서 합쳐야 합니다.
23. Write Types 비교
DynamoDB에서 여러 클라이언트가 동시에 같은 데이터를 쓸 때 어떻게 처리되는지 이해해야 합니다.
| 유형 | 설명 |
|---|---|
| Concurrent Writes | 두 번째 쓰기가 첫 번째 덮어씀 |
| Atomic Writes | 증가값 모두 적용 (value += 1 + 2 = 3) |
| Conditional Writes | 조건 충족 시에만 쓰기 (첫 번째만 성공) |
| Batch Writes | 여러 아이템 동시 쓰기 |
예시로 이해하기: 조회수가 0인 상태에서 두 사용자가 동시에 조회수를 1 증가시키려 한다면?
- Concurrent: 둘 다 0을 읽고 1로 덮어씀 → 결과 1 (잘못됨)
- Atomic: 각각 +1 적용 → 결과 2 (정확함)
- Conditional: 첫 번째만 성공, 두 번째는 재시도 필요
24. Large Objects 패턴
DynamoDB는 아이템당 최대 400KB만 저장할 수 있습니다. 이미지나 문서 같은 큰 파일은 어떻게 처리할까요? Amazon S3와 DynamoDB를 조합하면 효과적으로 해결할 수 있습니다.
문제
| 항목 | 설명 |
|---|---|
| DynamoDB | 아이템 최대 400KB |
| 저장 불가 | 이미지, 영상, 대용량 문서 등 |
패턴 1: 큰 객체 저장 (S3 + DynamoDB)
각 서비스의 강점을 활용하는 조합입니다:
- Amazon S3: 큰 객체 저장에 뛰어남
- DynamoDB: 작은 객체(메타데이터) 저장 및 빠른 검색에 뛰어남
쓰기 흐름:
Application
│
│ 1. 이미지 업로드
▼
┌─────────────────┐
│ Amazon S3 │ → 객체 키(URL) 반환
│ (이미지 저장) │
└─────────────────┘
│
│ 2. 메타데이터 저장
▼
┌─────────────────────────────────────────────────────────────┐
│ DynamoDB (Products 테이블) │
├─────────────┬──────────────┬────────────────────────────────┤
│ Product_ID │ Product_Name │ Image_URL │
├─────────────┼──────────────┼────────────────────────────────┤
│ PROD-001 │ 노트북 │ s3://bucket/images/laptop.jpg │
│ PROD-002 │ 키보드 │ s3://bucket/images/keyboard.jpg│
└─────────────────────────────────────────────────────────────┘💡 작은 데이터(메타데이터)는 DynamoDB에, 큰 데이터(이미지)는 S3에 효율적으로 저장합니다.
읽기 흐름:
Application (클라이언트)
│
│ 1. 메타데이터 조회
▼
┌─────────────────┐
│ DynamoDB │ → Product_ID, Product_Name, Image_URL 반환
└─────────────────┘
│
│ 2. Image_URL로 이미지 요청
▼
┌─────────────────┐
│ Amazon S3 │ → 이미지 바이너리 반환
└─────────────────┘
│
│ 3. 큰 객체 재구성
▼
Application (클라이언트에 이미지 표시)이 전략을 사용하면 다양한 상품을 대규모로 저장할 수 있습니다. 각 서비스를 적절하게 활용하는 완벽한 조합입니다.
패턴 2: S3 객체 메타데이터 인덱싱
S3에 저장된 객체를 DynamoDB로 인덱싱하여 검색 가능하게 만드는 패턴입니다.
왜 필요한가?
| 서비스 | 특징 |
|---|---|
| S3 | 대용량 객체 저장에 적합, 스캔 불가 |
| DynamoDB | 쿼리/검색에 뛰어남, 다양한 조건 검색 |
S3 버킷은 스캔이 되지 않고, 큰 객체를 저장하는 곳입니다. 객체의 속성을 알고 검색하려면 별도의 데이터베이스가 필요합니다.
아키텍처:
┌─────────────┐
│ Application │
└──────┬──────┘
│ 1. 파일 업로드
▼
┌─────────────────┐ ┌─────────────────┐
│ Amazon S3 │────▶│ S3 Event │
│ (객체 저장) │ │ Notification │
└─────────────────┘ └────────┬────────┘
│ 2. Lambda 트리거
▼
┌─────────────────┐
│ AWS Lambda │
│ (메타데이터 추출)│
└────────┬────────┘
│ 3. 메타데이터 저장
▼
┌─────────────────────────────────────────────────────────────┐
│ DynamoDB (S3_Objects_Metadata 테이블) │
├─────────────┬──────────┬──────────┬─────────┬───────────────┤
│ Object_Key │ Size │ Created │ Owner │ Content_Type │
├─────────────┼──────────┼──────────┼─────────┼───────────────┤
│ img/a.jpg │ 2.5MB │ 2024-01 │ user_1 │ image/jpeg │
│ doc/b.pdf │ 15MB │ 2024-01 │ user_2 │ application/pdf│
└─────────────────────────────────────────────────────────────┘DynamoDB 테이블로 가능한 쿼리:
# DynamoDB 테이블 상단에 애플리케이션을 만들면 다양한 쿼리 가능:
1. 특정 타임스탬프의 객체 찾기
→ "2024년 1월에 업로드된 모든 파일"
2. 고객이 사용한 총 스토리지 계산
→ "user_1이 사용한 총 용량은?"
3. 속성별 객체 목록화
→ "image/jpeg 타입의 모든 파일"
4. 특정 조건의 S3 객체 검색
→ "10MB 이상인 PDF 파일"조회 흐름:
Application
│
│ 1. 조건으로 쿼리
│ (예: "2024년 1월 업로드된 이미지")
▼
┌─────────────────┐
│ DynamoDB │ → 조건에 맞는 Object_Key 목록 반환
└─────────────────┘
│
│ 2. 필요한 객체 검색
▼
┌─────────────────┐
│ Amazon S3 │ → 실제 파일 반환
└─────────────────┘S3 + DynamoDB 조합 요약
| 패턴 | 용도 | 특징 |
|---|---|---|
| 큰 객체 저장 | 이미지, 영상 등 대용량 파일 저장 | DynamoDB에 URL만 저장 |
| 메타데이터 인덱싱 | S3 객체 검색/분석 | Lambda로 자동 인덱싱 |
💡 시험 포인트: 두 패턴 모두 S3와 DynamoDB의 강점을 활용하는 잘 알려진 조합입니다. 시험에 출제될 수 있습니다.
25. DynamoDB Operations
테이블의 데이터를 정리하거나 복사하는 운영 작업들입니다.
테이블 정리 (Table Cleanup)
테이블의 모든 아이템을 삭제해야 할 때 두 가지 방법이 있습니다.
방법 비교
| 방법 | 속도 | 비용 | 권장 상황 |
|---|---|---|---|
| Scan + DeleteItem | 매우 느림 | 비쌈 (RCU + WCU) | 일부 데이터만 삭제 |
| Drop + Recreate ⭐ | 빠름 | 저렴 (무료) | 전체 데이터 삭제 |
옵션 1: Scan + DeleteItem (비권장)
# 모든 아이템을 스캔하고 하나씩 삭제
┌─────────────────────────────────────────────────────────────┐
│ DynamoDB Table │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │Item 1│ │Item 2│ │Item 3│ │Item 4│ │Item 5│ ... (N개) │
│ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ │
└─────────────────────────────────────────────────────────────┘
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
Scan으로 Scan으로 Scan으로 Scan으로 Scan으로
읽기(RCU) 읽기(RCU) 읽기(RCU) 읽기(RCU) 읽기(RCU)
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
DeleteItem DeleteItem DeleteItem DeleteItem DeleteItem
(WCU) (WCU) (WCU) (WCU) (WCU)단점:
- 아이템 하나하나를 스캔하고 삭제
- 읽기(RCU) + 쓰기(WCU) 모두 소비
- 테이블이 클수록 시간과 비용이 급증
- 매우 느리고 비용이 많이 듦
옵션 2: Drop + Recreate (권장) ⭐
# 테이블을 삭제하고 동일한 설정으로 재생성
┌─────────────────────────────────────────────────────────────┐
│ DynamoDB Table │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │Item 1│ │Item 2│ │Item 3│ │ .... │ │Item N│ │
│ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ │
└─────────────────────────────────────────────────────────────┘
│
DeleteTable API
│
▼
(테이블 전체 삭제)
│
CreateTable API
(동일한 설정으로)
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 새로운 빈 DynamoDB Table │
│ (비어있음) │
└─────────────────────────────────────────────────────────────┘장점:
- 테이블 삭제 후 같은 이름/설정으로 재생성
- RCU/WCU 소비 없음 (API 호출만)
- 빠르고 효율적이며 저렴함
💡 시험 포인트: 전체 테이블 데이터를 삭제해야 한다면, Scan + DeleteItem보다 Drop + Recreate가 훨씬 효율적입니다.
테이블 복사 (Copying a DynamoDB Table)
DynamoDB 테이블을 계정, 리전, 또는 다른 환경으로 복사하는 방법들입니다.
방법 비교
| 방법 | 복잡도 | 비용 | 특징 |
|---|---|---|---|
| AWS Data Pipeline | 높음 | 중간 | EMR 클러스터 + S3 사용 |
| Backup and Restore ⭐ | 낮음 | 낮음 | 가장 간편하고 권장됨 |
| Scan + PutItem/BatchWriteItem | 중간 | 높음 | 직접 코드 작성 필요 |
옵션 1: AWS Data Pipeline
Amazon EMR 클러스터를 사용하여 테이블을 복사합니다.
┌──────────────────┐
│ Source Table │
│ (DynamoDB) │
└────────┬─────────┘
│
│ 1. 데이터 읽기
▼
┌──────────────────┐
│ Amazon EMR │ ← AWS Data Pipeline이 관리
│ (클러스터) │
└────────┬─────────┘
│
│ 2. S3에 임시 저장
▼
┌──────────────────┐
│ Amazon S3 │ (중간 저장소)
│ (임시 파일) │
└────────┬─────────┘
│
│ 3. S3에서 읽기
▼
┌──────────────────┐
│ Amazon EMR │
│ (클러스터) │
└────────┬─────────┘
│
│ 4. 데이터 쓰기
▼
┌──────────────────┐
│ Target Table │
│ (DynamoDB) │
└──────────────────┘특징:
- 복잡한 설정 필요
- EMR 클러스터 비용 발생
- S3를 중간 저장소로 사용
- 대용량 마이그레이션에 적합
옵션 2: Backup and Restore (권장) ⭐
AWS 백업 기능을 사용한 가장 간단한 방법입니다.
┌──────────────────┐
│ Source Table │
│ (DynamoDB) │
└────────┬─────────┘
│
│ 1. Create Backup
▼
┌──────────────────┐
│ Backup │ (AWS 관리)
│ (자동 저장) │
└────────┬─────────┘
│
│ 2. Restore to New Table
▼
┌──────────────────┐
│ Target Table │
│ (DynamoDB) │
│ (새 이름 가능) │
└──────────────────┘장점:
- 가장 간단하고 권장되는 방법
- 코드 작성 불필요
- AWS 콘솔에서 클릭 몇 번으로 완료
- 동일 리전/다른 리전 모두 가능
옵션 3: Scan + PutItem/BatchWriteItem
직접 코드를 작성하여 복사합니다.
┌──────────────────┐
│ Source Table │
│ (DynamoDB) │
└────────┬─────────┘
│
│ 1. Scan (읽기)
▼
┌──────────────────┐
│ Your Code │ (Lambda, EC2, 로컬 등)
│ - Scan │
│ - Write │
└────────┬─────────┘
│
│ 2. PutItem / BatchWriteItem
▼
┌──────────────────┐
│ Target Table │
│ (DynamoDB) │
└──────────────────┘특징:
- 직접 코드 작성 필요 (Python boto3, Node.js SDK 등)
- 데이터 변환/필터링 가능
- RCU + WCU 소비
- 세밀한 제어가 필요할 때 사용
테이블 복사 방법 요약
┌─────────────────────────────────────────────────────────────────────┐
│ 테이블 복사 방법 선택 가이드 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 간단한 복사가 필요한가? │
│ │ │
│ ├── Yes → Backup and Restore ⭐ (권장) │
│ │ │
│ └── No (데이터 변환 필요) │
│ │ │
│ ├── 대용량 + 인프라 있음 → AWS Data Pipeline │
│ │ │
│ └── 커스텀 로직 필요 → Scan + PutItem/BatchWriteItem │
│ │
└─────────────────────────────────────────────────────────────────────┘💡 시험 포인트:
- 단순 복사 → Backup and Restore 선택
- 대용량 마이그레이션 → AWS Data Pipeline 고려
- 커스텀 변환 필요 → Scan + Write 직접 코딩
26. DynamoDB 보안 & 기능
DynamoDB의 보안 설정과 부가 기능들입니다.
보안
| 항목 | 설명 |
|---|---|
| 네트워크 | VPC Endpoint (인터넷 없이 접근) |
| 접근 제어 | IAM |
| 암호화 | KMS (저장), SSL/TLS (전송) |
백업
| 기능 | 설명 |
|---|---|
| Backup & Restore | 수동 백업 |
| PITR | Point-in-time Recovery (성능 영향 없음) |
PITR(Point-in-time Recovery): 최근 35일 내 원하는 시점으로 테이블을 복원할 수 있습니다. 실수로 데이터를 삭제해도 복구 가능합니다.
글로벌 기능
| 기능 | 설명 |
|---|---|
| Global Tables | 멀티 리전, 멀티 액티브, 완전 복제 |
| DynamoDB Local | 로컬 개발/테스트 (오프라인) |
| AWS DMS | 다른 DB에서 DynamoDB로 마이그레이션 |
Global Tables: 서울, 도쿄, 버지니아 등 여러 리전에 동일한 테이블을 두고 자동으로 동기화합니다. 전 세계 사용자에게 낮은 지연 시간을 제공하고, 한 리전이 장애가 나도 다른 리전에서 서비스를 계속할 수 있습니다.
27. Fine-Grained Access Control
사용자마다 자신의 데이터에만 접근하도록 제한하는 기능입니다. 멀티테넌트 애플리케이션에서 A 사용자가 B 사용자의 데이터를 볼 수 없게 합니다.
개요
- Cognito/Web Identity Federation으로 사용자별 AWS 자격 증명
- IAM 조건으로 DynamoDB API 접근 제한
조건 예시
| 조건 | 설명 |
|---|---|
| LeadingKeys | Primary Key 기반 행 수준 접근 제한 |
| Attributes | 특정 속성만 조회 허용 |
{
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": ["${cognito-identity.amazonaws.com:sub}"]
}
}
}→ 사용자는 자신의 데이터만 접근 가능
실제 예시: 모바일 앱에서 사용자가 Cognito로 로그인하면 고유한 ID(sub)를 받습니다. IAM 정책에서 "user_id가 자신의 sub과 같은 아이템만 접근 가능"으로 설정하면, 각 사용자는 자신의 데이터만 볼 수 있습니다.
핵심 요약
시험에서 자주 출제되는 핵심 개념들을 정리합니다.
Capacity 계산 (시험 필수!)
| 유형 | 공식 |
|---|---|
| WCU | 쓰기/초 × (아이템 크기 / 1KB) |
| RCU (Strong) | 읽기/초 × (아이템 크기 / 4KB) |
| RCU (Eventually) | 읽기/초 / 2 × (아이템 크기 / 4KB) |
| Transactional | 위 값 × 2 |
인덱스
| 인덱스 | 생성 시점 | PK 변경 | Throttling |
|---|---|---|---|
| LSI | 테이블 생성 시만 | ❌ | 메인 테이블 사용 |
| GSI | 언제든 | ✅ | 메인에 영향 |
캐시
| 서비스 | 용도 |
|---|---|
| DAX | DynamoDB 캐시 (Hot Key 해결) |
| ElastiCache | 집계 결과 캐시 |
시험 팁: WCU/RCU 계산 문제가 자주 출제됩니다. 항상 1) 초당 횟수 2) 아이템 크기 올림 3) 일관성 모드(Eventually는 /2) 4) Transaction은 x2 를 체크하세요!