2026. 6. 8. 09:12ㆍCloud/AWS
새 서비스를 설계할 때 "DB는 뭘로 하지?"라는 질문이 나옵니다. AWS에서 가장 많이 비교되는 조합이 RDS와 DynamoDB입니다. 둘 다 관리형 서비스지만, 데이터 모델, 확장 방식, 비용 구조가 근본적으로 다릅니다. 잘못된 선택은 6개월 뒤 마이그레이션이라는 비용으로 돌아옵니다.
요약
| 기준 | RDS | DynamoDB |
|---|---|---|
| 데이터 모델 | 관계형 (테이블, 행, 열, JOIN) | Key-Value / Document (스키마리스) |
| 쿼리 | SQL (복잡한 JOIN, 서브쿼리 가능) | 기본키 기반 조회, 제한적 쿼리 |
| 확장 방식 | 수직 확장 (인스턴스 크기 변경) | 수평 확장 (자동 파티셔닝) |
| 지연 시간 | 수 ms~수십 ms (쿼리 복잡도에 따라) | 한 자릿수 ms (일관적) |
| 운영 | 인스턴스 관리, 패치, 백업 스케줄 설정 | 서버리스, 인프라 관리 불필요 |
| 비용 모델 | 인스턴스 시간 + 스토리지 + I/O | 요청당 과금 또는 프로비저닝 용량 |
| 트랜잭션 | ACID 완전 지원 | 제한적 트랜잭션 (100개 항목, 4MB 이내) |
| 추천 상황 | 복잡한 관계, 리포팅, 정합성이 중요한 시스템 | 대규모 트래픽, 단순 접근 패턴, 서버리스 아키텍처 |
1. 왜 이 비교가 필요한가
"관계형이 익숙하니까 RDS"로 결정하거나, "서버리스가 트렌드니까 DynamoDB"로 결정하는 경우가 많습니다. 두 가지 모두 위험한 접근입니다.
실무에서 흔히 발생하는 시나리오:
- RDS를 선택했는데 트래픽이 급증: 이벤트 기간에 초당 수만 건의 쓰기가 발생하면, RDS는 인스턴스 크기를 올려야 합니다. 수직 확장에는 한계가 있고, Read Replica 추가에도 시간이 걸립니다.
- DynamoDB를 선택했는데 복잡한 조회가 필요: "지난달 주문 중 환불된 건의 상품별 매출을 집계해줘"라는 요구가 들어오면, DynamoDB에서는 이 쿼리를 직접 수행할 수 없습니다.
데이터베이스 선택은 되돌리기 어려운 결정입니다. 데이터 모델, 접근 패턴, 확장 요구사항을 기준으로 판단해야 합니다.
2. RDS란
Amazon RDS(Relational Database Service)는 관계형 데이터베이스를 관리형으로 제공하는 서비스입니다.
핵심 특성
| 특성 | 설명 |
|---|---|
| 지원 엔진 | MySQL, PostgreSQL, MariaDB, Oracle, SQL Server, Aurora |
| 데이터 모델 | 테이블 기반, 정규화된 스키마, 외래 키, JOIN |
| 확장 방식 | 수직 확장 (인스턴스 변경) + Read Replica (읽기 분산) |
| 가용성 | Multi-AZ 배포 (자동 장애 조치) |
| 백업 | 자동 백업 (최대 35일) + 수동 스냅샷 |
| 최대 스토리지 | 128TB (Aurora), 64TB (기타 엔진) |
RDS가 잘하는 것
- 복잡한 관계 표현: 사용자, 주문, 상품, 결제, 배송 같은 엔터티 간 관계를 외래 키와 JOIN으로 표현
- ACID 트랜잭션: "결제 성공 → 재고 차감 → 주문 상태 변경"을 하나의 트랜잭션으로 보장
- 유연한 쿼리: 사전에 정의하지 않은 조건으로도 데이터를 조회 가능 (Ad-hoc Query)
- 리포팅/분석: GROUP BY, HAVING, 윈도우 함수 등으로 집계 분석
3. DynamoDB란
Amazon DynamoDB는 완전 관리형 NoSQL 데이터베이스로, Key-Value와 Document 모델을 지원합니다.
핵심 특성
| 특성 | 설명 |
|---|---|
| 데이터 모델 | Key-Value / Document (JSON 유사 구조) |
| 스키마 | 파티션 키(PK)와 정렬 키(SK)만 필수, 나머지 속성은 자유 |
| 확장 방식 | 자동 수평 확장 (파티셔닝) |
| 지연 시간 | 한 자릿수 밀리초 (규모와 무관하게 일관) |
| 용량 모드 | On-demand (요청당 과금) / Provisioned (용량 사전 지정) |
| 글로벌 테이블 | Multi-Region 복제 지원 (Active-Active) |
| 최대 항목 크기 | 400KB |
DynamoDB가 잘하는 것
- 대규모 트래픽 처리: 초당 수백만 건의 요청을 한 자릿수 ms로 처리
- 예측 가능한 성능: 데이터가 10GB든 10TB든 응답 시간이 일정
- 서버리스 통합: Lambda + API Gateway + DynamoDB 조합으로 인프라 관리 제로
- 글로벌 복제: Global Tables로 Multi-Region Active-Active 구현
4. 구조 비교
RDS 아키텍처
클라이언트 → RDS Endpoint → Primary Instance (Read/Write)
→ Read Replica (Read Only) × N개
→ Standby Instance (Multi-AZ 장애 조치용)
- 하나의 Primary 인스턴스가 모든 쓰기를 처리합니다.
- Read Replica로 읽기 부하를 분산할 수 있지만, 쓰기 확장은 인스턴스 크기에 의존합니다.
- Multi-AZ 배포 시 Standby 인스턴스가 자동 장애 조치를 담당합니다.
DynamoDB 아키텍처
클라이언트 → DynamoDB Endpoint → 파티션 1 (PK hash 기반 분산)
→ 파티션 2
→ 파티션 N (자동 분할)
- 파티션 키의 해시값으로 데이터가 자동 분산됩니다.
- 트래픽이 늘면 파티션이 자동으로 분할(split)됩니다.
- 클라이언트는 파티션 구조를 알 필요 없이 단일 엔드포인트로 접근합니다.
5. 데이터 모델 차이
RDS: 정규화된 관계 모델
-- 사용자 테이블
CREATE TABLE users (
user_id INT PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(255) UNIQUE
);
-- 주문 테이블 (사용자와 1:N 관계)
CREATE TABLE orders (
order_id INT PRIMARY KEY,
user_id INT REFERENCES users(user_id),
total_amount DECIMAL(10,2),
status VARCHAR(20),
created_at TIMESTAMP
);
-- 주문 상품 테이블 (주문과 N:M 관계)
CREATE TABLE order_items (
order_id INT REFERENCES orders(order_id),
product_id INT REFERENCES products(product_id),
quantity INT,
price DECIMAL(10,2)
);
-- 복잡한 조회: 특정 사용자의 최근 주문과 상품 정보
SELECT u.name, o.order_id, p.product_name, oi.quantity
FROM users u
JOIN orders o ON u.user_id = o.user_id
JOIN order_items oi ON o.order_id = oi.order_id
JOIN products p ON oi.product_id = p.product_id
WHERE u.user_id = 123
ORDER BY o.created_at DESC
LIMIT 10;
데이터를 정규화해서 중복을 제거하고, 필요할 때 JOIN으로 조합합니다. 쿼리 패턴을 사전에 확정하지 않아도 됩니다.
DynamoDB: 접근 패턴 기반 모델
// 단일 테이블 설계 (Single Table Design)
// PK: USER#123, SK: ORDER#2024-01-15#001
{
"PK": "USER#123",
"SK": "ORDER#2026-01-15#001",
"order_id": "001",
"total_amount": 45000,
"status": "delivered",
"items": [
{"product_id": "P001", "name": "키보드", "quantity": 1, "price": 35000},
{"product_id": "P002", "name": "마우스패드", "quantity": 2, "price": 5000}
]
}
접근 패턴(Access Pattern)을 먼저 정의하고, 그에 맞게 테이블을 설계합니다. "이 사용자의 최근 주문 10건을 조회"라는 패턴이 확정되어 있다면 위 구조로 한 번의 쿼리로 모든 정보를 가져올 수 있습니다.
핵심 차이
| 관점 | RDS | DynamoDB |
|---|---|---|
| 설계 시작점 | 데이터 구조(엔터티, 관계)부터 설계 | 접근 패턴(쿼리 요구사항)부터 설계 |
| 스키마 변경 | ALTER TABLE로 컬럼 추가/변경 (마이그레이션 필요) | 새 속성을 그냥 추가 (스키마리스) |
| 데이터 중복 | 정규화로 최소화 | 성능을 위해 의도적으로 비정규화 |
| 쿼리 유연성 | 높음 (임의 조건 조합 가능) | 낮음 (사전 설계된 패턴만 효율적) |
6. 확장성 차이
RDS: 수직 확장 + 읽기 분산
| 확장 방법 | 설명 | 한계 |
|---|---|---|
| 인스턴스 업그레이드 | db.m6g.large → db.m6g.4xlarge | 최대 인스턴스 크기 제한, 변경 시 다운타임 발생 가능 |
| Read Replica | 읽기 부하 분산 (최대 15개) | 쓰기는 분산 불가, 복제 지연(Replication Lag) 발생 |
| Aurora Auto Scaling | Reader 인스턴스 자동 추가/제거 | 쓰기 확장은 여전히 단일 Writer |
RDS에서 쓰기 성능의 한계는 단일 Primary 인스턴스의 CPU/메모리/IOPS입니다. 이를 넘어서면 샤딩을 직접 구현하거나 아키텍처를 변경해야 합니다.
DynamoDB: 자동 수평 확장
| 확장 방법 | 설명 | 한계 |
|---|---|---|
| 자동 파티셔닝 | 트래픽 증가 시 파티션 자동 분할 | 핫 파티션(Hot Partition) 발생 시 스로틀링 |
| On-demand 모드 | 트래픽 규모에 관계없이 자동 대응 | 이전 피크의 2배까지 즉시 확장, 그 이상은 점진적 |
| Auto Scaling | Provisioned 모드에서 자동 용량 조정 | 스케일링 반응 시간 1~2분 소요 |
DynamoDB는 파티션 키만 잘 설계하면 사실상 무한에 가까운 수평 확장이 가능합니다. 다만 특정 파티션 키에 트래픽이 집중되는 핫 파티션 문제를 주의해야 합니다.
확장성 판단 기준
| 상황 | 권장 선택 |
|---|---|
| 읽기 위주, 쓰기가 초당 수천 건 이하 | RDS (Read Replica로 충분) |
| 쓰기가 초당 수만 건 이상 | DynamoDB |
| 트래픽 패턴이 예측 불가 (갑자기 10배 증가) | DynamoDB On-demand |
| 데이터 크기가 수 TB 이상 | DynamoDB (RDS는 스토리지 한계 존재) |
7. 비용 비교
7.1 RDS 비용 구조
RDS는 인스턴스를 실행하는 동안 시간당 비용이 발생합니다.
| 항목 | 예시 (us-east-1, MySQL) |
|---|---|
| 인스턴스 | db.m6g.large: 약 $0.152/시간 (~$111/월) |
| 스토리지 (gp3) | $0.08/GB/월 |
| Multi-AZ | 인스턴스 비용 2배 |
| 백업 스토리지 | 무료 (DB 크기까지), 초과 시 $0.095/GB/월 |
| 데이터 전송 | 리전 내 무료, 리전 간 $0.02/GB |
예시: db.m6g.large, Multi-AZ, 100GB gp3 스토리지
- 인스턴스: $0.152 × 2 (Multi-AZ) × 730시간 = $221.92/월
- 스토리지: $0.08 × 100GB × 2 (Multi-AZ) = $16/월
- 합계: 약 $238/월 (트래픽이 없어도 고정 비용 발생)
7.2 DynamoDB 비용 구조
DynamoDB는 두 가지 과금 모드를 제공합니다.
On-demand 모드 (us-east-1, Standard 테이블):
| 항목 | 단가 |
|---|---|
| 쓰기 요청 | $0.625 / 100만 WRU |
| 읽기 요청 | $0.125 / 100만 RRU |
| 스토리지 | $0.25/GB/월 (첫 25GB 무료) |
Provisioned 모드 (us-east-1):
| 항목 | 단가 |
|---|---|
| 쓰기 용량 | $0.00065/WCU/시간 (~$0.4745/WCU/월) |
| 읽기 용량 | $0.00013/RCU/시간 (~$0.0949/RCU/월) |
| 스토리지 | $0.25/GB/월 (첫 25GB 무료) |
7.3 비용 시나리오 비교
시나리오 A: 소규모 SaaS (일 100만 요청, 50GB 데이터)
| 항목 | RDS (db.m6g.large, Multi-AZ) | DynamoDB (On-demand) |
|---|---|---|
| 컴퓨팅/요청 | $221.92 (고정) | 쓰기 50만 × $0.625/100만 = $0.31, 읽기 50만 × $0.125/100만 = $0.06 |
| 스토리지 | $16 | $0.25 × 25GB = $6.25 (25GB 무료 적용) |
| 월 합계 | ~$238 | ~$7 |
이 시나리오에서는 DynamoDB가 훨씬 저렴합니다. 트래픽이 적을 때 On-demand 모드의 강점이 드러납니다.
시나리오 B: 대규모 서비스 (일 1억 요청, 500GB 데이터, 안정적 트래픽)
| 항목 | RDS (db.m6g.4xlarge, Multi-AZ) | DynamoDB (Provisioned) |
|---|---|---|
| 컴퓨팅/용량 | ~$890 (인스턴스) | WCU 1000 × $0.4745 + RCU 2000 × $0.0949 = $664.30 |
| 스토리지 | $80 | $0.25 × 475GB = $118.75 |
| 월 합계 | ~$970 | ~$783 |
대규모에서도 DynamoDB가 비용 효율적일 수 있지만, 차이가 줄어듭니다. 다만 GSI(Global Secondary Index)를 추가하면 DynamoDB 비용이 빠르게 증가합니다.
위 가격은 us-east-1 기준이며, 리전별로 상이할 수 있습니다. 실제 비용은 AWS Pricing Calculator로 확인해야 합니다. DynamoDB On-demand 모드의 쓰기 단가($0.625/100만 WRU)와 읽기 단가($0.125/100만 RRU)는 2026년 6월 기준입니다.
7.4 비용 판단 핵심
| 상황 | 비용 유리한 선택 |
|---|---|
| 트래픽이 적거나 불규칙 | DynamoDB On-demand (사용한 만큼만 지불) |
| 트래픽이 안정적이고 예측 가능 | DynamoDB Provisioned 또는 RDS Reserved Instance |
| 복잡한 쿼리 + 리포팅 필요 | RDS (별도 분석 도구 없이 SQL로 해결) |
| GSI가 3개 이상 필요한 접근 패턴 | RDS가 비용 면에서 유리할 수 있음 |
8. 운영 복잡도 차이
| 기준 | RDS | DynamoDB |
|---|---|---|
| 인스턴스 관리 | 인스턴스 타입 선택, 크기 변경 필요 | 없음 (서버리스) |
| OS/엔진 패치 | 유지보수 윈도우 설정 필요 | 없음 |
| 백업 | 자동 백업 설정 + 보존 기간 관리 | PITR 활성화만 하면 자동 |
| 스케일링 | 수동 또는 Auto Scaling 설정 | 자동 (On-demand) 또는 Auto Scaling |
| 모니터링 | CPU, 메모리, 디스크, 커넥션 수 등 | 읽기/쓰기 용량, 스로틀링, 지연 시간 |
| 장애 복구 | Multi-AZ 설정 시 자동 Failover (30~60초) | 자동 (사용자 개입 불필요) |
| 연결 관리 | Connection Pool 크기 관리 필요 | HTTP 기반, 연결 풀 불필요 |
| 스키마 변경 | DDL 실행, 마이그레이션 도구 사용 | 스키마리스 (속성 자유 추가) |
RDS 운영 시 주의점
- 커넥션 고갈: 애플리케이션이 많아지면 DB 커넥션이 부족해질 수 있습니다. RDS Proxy를 사용하면 커넥션 풀링을 관리할 수 있습니다.
- 패치 다운타임: 엔진 패치 시 수 초~수 분의 다운타임이 발생할 수 있습니다. Multi-AZ 환경에서는 Failover로 최소화합니다.
- 스토리지 Full: 디스크가 가득 차면 DB가 중지됩니다. Auto Scaling Storage를 활성화하거나 CloudWatch 알람을 설정해야 합니다.
DynamoDB 운영 시 주의점
- 핫 파티션: 특정 파티션 키에 트래픽이 집중되면 스로틀링이 발생합니다. 파티션 키 설계가 핵심입니다.
- GSI 비용 폭증: GSI를 추가할 때마다 쓰기 비용이 배로 증가합니다. GSI 설계를 신중하게 해야 합니다.
- 항목 크기 제한: 단일 항목 최대 400KB. 큰 데이터는 S3에 저장하고 참조만 보관해야 합니다.
9. 트랜잭션과 일관성
| 기준 | RDS | DynamoDB |
|---|---|---|
| ACID 트랜잭션 | 완전 지원 (BEGIN, COMMIT, ROLLBACK) | 제한적 (TransactWriteItems: 최대 100개 항목, 4MB) |
| 격리 수준 | Serializable, Repeatable Read 등 선택 가능 | 항목 단위 직렬화 |
| 일관성 | 강한 일관성 (Strong Consistency) | Eventually Consistent (기본) / Strongly Consistent (선택) |
| 외래 키 제약 | 지원 | 미지원 (애플리케이션에서 관리) |
RDS 트랜잭션 예시
BEGIN;
UPDATE accounts SET balance = balance - 50000 WHERE account_id = 'A001';
UPDATE accounts SET balance = balance + 50000 WHERE account_id = 'A002';
INSERT INTO transactions (from_id, to_id, amount, created_at)
VALUES ('A001', 'A002', 50000, NOW());
COMMIT;
세 작업이 모두 성공하거나 모두 롤백됩니다. 부분 실패가 불가능합니다.
DynamoDB 트랜잭션 예시
dynamodb.transact_write_items(
TransactItems=[
{
'Update': {
'TableName': 'Accounts',
'Key': {'PK': {'S': 'ACCOUNT#A001'}},
'UpdateExpression': 'SET balance = balance - :amount',
'ExpressionAttributeValues': {':amount': {'N': '50000'}}
}
},
{
'Update': {
'TableName': 'Accounts',
'Key': {'PK': {'S': 'ACCOUNT#A002'}},
'UpdateExpression': 'SET balance = balance + :amount',
'ExpressionAttributeValues': {':amount': {'N': '50000'}}
}
}
]
)
DynamoDB도 트랜잭션을 지원하지만, 최대 100개 항목 또는 4MB 이내라는 제약이 있습니다. 또한 트랜잭션 요청은 일반 요청 대비 2배의 용량을 소비합니다.
판단 기준
- 금융 거래, 재고 관리, 결제: 복잡한 트랜잭션과 강한 일관성이 필수 → RDS
- 소셜 미디어 좋아요, 조회수, 세션 데이터: 약간의 비일관성 허용 가능 → DynamoDB
10. 선택 기준
10.1 의사결정 플로우
어떤 데이터를 저장하는가?
│
├── 엔터티 간 복잡한 관계가 있는가? (1:N, N:M, JOIN 필요)
│ ├── Yes → 접근 패턴이 확정되어 있는가?
│ │ ├── Yes + 대규모 트래픽 → DynamoDB (Single Table Design)
│ │ └── No 또는 다양한 Ad-hoc 쿼리 필요 → RDS
│ └── No → 단순 Key-Value 조회 위주인가?
│ ├── Yes → DynamoDB
│ └── 집계/리포팅도 필요 → RDS
│
├── 확장 요구사항은?
│ ├── 초당 수만 건 이상 쓰기 → DynamoDB
│ ├── 예측 불가한 트래픽 스파이크 → DynamoDB On-demand
│ └── 안정적인 트래픽, 수천 건 이하 → RDS
│
└── 운영 환경 제약은?
├── 서버리스 아키텍처 (Lambda 기반) → DynamoDB
├── 기존 SQL 기반 애플리케이션 마이그레이션 → RDS
└── 팀에 DynamoDB 설계 경험이 없음 → RDS (학습 비용 고려)
10.2 RDS를 선택해야 하는 경우
| 상황 | 이유 |
|---|---|
| 복잡한 관계와 JOIN이 필수 | DynamoDB에서는 JOIN을 애플리케이션에서 구현해야 함 |
| Ad-hoc 쿼리가 빈번 | "어떤 조건으로 데이터를 볼지" 사전에 확정할 수 없는 환경 |
| 리포팅/분석 기능 필요 | SQL 기반 집계, GROUP BY, 서브쿼리 활용 |
| ACID 트랜잭션이 복잡 | 다수 테이블에 걸친 복잡한 트랜잭션 |
| 기존 SQL 기반 시스템 마이그레이션 | 코드 변경 최소화 |
10.3 DynamoDB를 선택해야 하는 경우
| 상황 | 이유 |
|---|---|
| 한 자릿수 ms 응답이 필수 | 규모와 무관하게 일관된 지연 시간 보장 |
| 초당 수만~수백만 건 처리 | 자동 수평 확장으로 대응 |
| 접근 패턴이 명확하고 제한적 | PK/SK 기반 조회로 충분한 경우 |
| 서버리스 아키텍처 | Lambda와 자연스럽게 통합 |
| 트래픽 변동이 극심 | On-demand 모드로 유휴 비용 제거 |
| 글로벌 서비스 | Global Tables로 Multi-Region 복제 |
11. 실무 예시
사례 1: 전자상거래 플랫폼
문제: 상품 카탈로그, 사용자 정보, 주문, 결제를 하나의 DB로 처리하려고 합니다.
설계 판단:
이 시나리오에서는 "모든 것을 하나의 DB로"가 아니라, 도메인별로 적합한 DB를 선택하는 것이 운영 환경에서의 일반적인 접근입니다.
| 도메인 | 선택 | 이유 |
|---|---|---|
| 사용자/주문/결제 | RDS (PostgreSQL) | 관계가 복잡하고, 트랜잭션 정합성 필수 |
| 상품 카탈로그 | DynamoDB | 상품 조회가 PK 기반, 읽기 트래픽 대량, 속성이 상품마다 다름 |
| 장바구니/세션 | DynamoDB | TTL로 자동 만료, 높은 쓰기 빈도, 정합성 요구 낮음 |
| 주문 이력 조회 | DynamoDB | 사용자별 최근 주문 N건 조회 패턴이 명확 |
결과: RDS는 핵심 비즈니스 로직(결제, 재고)을 담당하고, DynamoDB는 높은 트래픽과 단순 접근 패턴을 처리합니다. 하나의 서비스에서 두 DB를 함께 사용하는 것은 AWS 환경에서 흔한 패턴입니다.
사례 2: IoT 센서 데이터 수집
문제: 10만 대의 IoT 장치에서 5초마다 센서 데이터를 전송합니다. 초당 20,000건의 쓰기가 발생합니다.
설계 판단:
- RDS로는 초당 20,000건 쓰기를 감당하기 어렵습니다. 최대 인스턴스를 사용해도 디스크 IOPS 한계에 부딪힙니다.
- DynamoDB On-demand 모드로 설정하면 별도 용량 계획 없이 자동 확장됩니다.
// DynamoDB 테이블 설계
{
"PK": "DEVICE#sensor-001",
"SK": "2026-06-08T10:30:05Z",
"temperature": 23.5,
"humidity": 65,
"battery": 87
}
- 파티션 키: 장치 ID (10만 개의 고유 키로 트래픽 분산)
- 정렬 키: 타임스탬프 (시간순 조회 가능)
- TTL 설정: 30일 이후 자동 삭제 (비용 절감)
이 시나리오에서 RDS를 선택했다면 샤딩을 직접 구현하거나 Amazon Timestream 같은 시계열 DB를 별도로 검토해야 합니다.
사례 3: 사내 ERP 시스템
문제: 직원 50명이 사용하는 ERP 시스템. 인사, 급여, 프로젝트 관리 기능이 필요합니다.
설계 판단:
- 트래픽이 낮고 (동시 사용자 50명 이하), 데이터 간 관계가 복잡합니다.
- "특정 부서의 지난 분기 프로젝트별 인건비를 산출해줘" 같은 Ad-hoc 쿼리가 빈번합니다.
- 이 상황에서 DynamoDB를 선택하면 모든 집계를 애플리케이션 레벨에서 구현해야 합니다.
결론: RDS (PostgreSQL)가 적합합니다. 트래픽이 낮으므로 가장 작은 인스턴스로도 충분하고, SQL의 유연성이 운영 효율을 높입니다.
12. 함께 사용하는 패턴
실무에서는 RDS와 DynamoDB를 병행하는 경우가 많습니다.
| 패턴 | 설명 |
|---|---|
| CQRS | 쓰기는 RDS에서 처리, 읽기 최적화 뷰는 DynamoDB에 비정규화 저장 |
| 캐시 계층 | RDS가 원본, DynamoDB(또는 ElastiCache)가 자주 조회되는 데이터 캐시 |
| 이벤트 소싱 | RDS에 핵심 상태 저장, DynamoDB Streams로 이벤트 전파 |
| 도메인 분리 | 트랜잭션 필수 도메인은 RDS, 고처리량 도메인은 DynamoDB |
하나의 서비스에서 RDS와 DynamoDB를 함께 사용할 때, DynamoDB를 "읽기 최적화 저장소"로 활용하는 CQRS 패턴은 높은 읽기 성능과 데이터 정합성을 동시에 확보할 수 있습니다. RDS의 변경 이벤트를 Lambda로 받아서 DynamoDB에 비정규화된 뷰를 동기화하는 구조입니다.
13. 자주 하는 실수
- "RDS가 익숙하니까"로 선택하는 것: 초당 수만 건의 쓰기가 예상되는데 팀이 SQL에 익숙하다는 이유로 RDS를 선택하면, 6개월 뒤 성능 한계에 부딪힙니다. 접근 패턴이 단순하면 DynamoDB 학습 비용을 감수할 가치가 있습니다.
- DynamoDB에서 RDS처럼 쓰는 것: DynamoDB를 관계형 모델로 설계하면(테이블을 여러 개 만들고 애플리케이션에서 JOIN), RDS보다 느리고 비싸고 복잡해집니다. Single Table Design을 제대로 학습해야 합니다.
- GSI를 과도하게 추가하는 것: DynamoDB에서 새로운 쿼리 패턴이 필요할 때마다 GSI를 추가하면 쓰기 비용이 배로 증가합니다. GSI 3개 이상이면 설계를 재검토하는 것이 좋습니다.
- RDS 인스턴스 크기를 과대 선정하는 것: 초기에 "혹시 모르니까" 큰 인스턴스를 선택하면 매월 불필요한 비용이 발생합니다. 작게 시작하고 CloudWatch 메트릭을 보며 올리는 것이 운영 비용을 줄입니다.
- DynamoDB에서 Scan을 자주 사용하는 것: Scan은 테이블 전체를 읽으므로 비용과 성능 모두에 악영향을 줍니다. Scan이 필요하다면 접근 패턴 설계를 다시 검토해야 합니다.
14. 정리
- RDS는 복잡한 관계, ACID 트랜잭션, 유연한 쿼리가 필요한 시스템에 적합합니다.
- DynamoDB는 대규모 트래픽, 한 자릿수 ms 응답, 서버리스 아키텍처에 적합합니다.
- "어떤 것이 더 좋다"가 아니라, 데이터 모델과 접근 패턴에 따라 선택이 달라집니다.
- 실무에서는 하나의 서비스 내에서도 도메인별로 RDS와 DynamoDB를 병행하는 것이 일반적입니다.
- 가장 중요한 판단 기준은 접근 패턴이 사전에 확정 가능한지, 그리고 엔터티 간 관계를 JOIN으로 표현해야 하는지입니다.
참고 문서
'Cloud > AWS' 카테고리의 다른 글
| AWS CloudFront란 무엇인가: CDN 동작 원리와 캐시 전략 (0) | 2026.06.07 |
|---|---|
| AWS Lambda 기본 구조: 서버리스 아키텍처와 Cold Start 이해하기 (0) | 2026.06.07 |
| AWS ECS vs EKS 차이: 컨테이너 오케스트레이션 선택 기준 (0) | 2026.06.06 |
| AWS S3 기본 개념: 버킷 정책, 버전 관리, 수명 주기 설계 (0) | 2026.06.05 |
| ALB와 NLB 차이: 언제 어떤 Load Balancer를 선택할까 (0) | 2026.06.01 |