
이번 주 목표
SAA 시험에서 가장 자주 나오는 "이 요구사항엔 어떤 DB를 써야 하나?" 유형을 확실히 잡는다.글의 구성
- Part I. 개념편 — 각 서비스가 무엇이고, 어떻게 동작하는가
- Part II. 비교편 — 네 서비스를 나란히 놓고 판별하기
- Part III. 비용·최적화편 — 같은 아키텍처에서 돈을 어떻게 아끼는가
SAA 시험은 "서비스 이름 암기"가 아니라 요구사항 → 서비스 선택 문제로 나온다.
문제는 보통 이렇게 생겼다.
"한 스타트업이 모바일 게임을 운영한다. 사용자 프로필은 단순한 키-값 형태이고,
트래픽은 이벤트 때마다 수십 배로 튄다. 운영 인력은 최소화하고 싶다.
어떤 데이터베이스를 선택해야 하는가?"
여기서 "단순한 키-값", "트래픽 급변", "운영 최소화"라는 세 단어가 곧 DynamoDB를 가리킨다.
즉 시험은 키워드 → 서비스 매핑 능력을 묻는다.
DB 영역은 시험 도메인 1(복원력 있는 아키텍처), 도메인 2(고성능 아키텍처),
도메인 4(비용 최적화)에 모두 걸쳐 있어서 출제 비중이 특히 높다.
| 문제 속 키워드 | 정답 방향 |
|---|---|
| JOIN, 트랜잭션, 기존 MySQL/PostgreSQL 마이그레이션 | RDS |
| 고성능 관계형 + 글로벌 + 최소 운영 부담 | Aurora |
| 밀리초 지연, 서버리스, 무한 확장, 단순 키-값 | DynamoDB |
| 마이크로초 지연, 캐시, 세션 저장, 리더보드 | ElastiCache (또는 DAX) |
본문에서 계속 나올 단어들이다. 여기서 한 번 정리하고 시작하자.
| 용어 | 뜻 | 비유 / 예시 |
|---|---|---|
| AZ (가용 영역) | 한 리전 안의 물리적으로 분리된 데이터센터 묶음 | 서울 리전 안에 데이터센터 건물이 4개 있는 것. 한 건물에 정전이 나도 나머지는 멀쩡 |
| 동기(Synchronous) 복제 | 원본과 복제본에 둘 다 저장이 끝나야 쓰기 성공으로 응답 | 계약서를 두 부 만들어 양쪽 다 도장 찍어야 계약 성립. 안전하지만 느림 |
| 비동기(Asynchronous) 복제 | 원본에만 저장하면 바로 성공 응답, 복제는 뒤따라감 | 일단 내 노트에 적고 나중에 친구에게 알려줌. 빠르지만 잠깐 정보가 다름 |
| 최종 일관성(Eventual Consistency) | 지금은 값이 다를 수 있지만 시간이 지나면 결국 같아짐 | 방금 쓴 댓글이 새로고침하면 잠깐 안 보이는 현상 |
| 강한 일관성(Strong Consistency) | 쓰기 직후 읽으면 무조건 최신값 | 계좌 잔액. 이체 직후 조회에 옛날 값이 나오면 큰일 |
| 페일오버(Failover) | 주 서버가 죽었을 때 대기 서버가 역할을 넘겨받는 것 | 주전 선수 부상 시 벤치 선수 자동 투입 |
| 엔드포인트(Endpoint) | 접속할 주소(DNS 이름) | mydb.abc123.ap-northeast-2.rds.amazonaws.com |
| 스로틀링(Throttling) | 허용 용량을 넘는 요청을 서비스가 거부하는 것 | 정원 초과라 입장 거부. 에러가 나면서 요청이 실패함 |
| 인메모리(In-memory) | 디스크가 아니라 RAM에 데이터를 두는 것 | 디스크가 창고라면 RAM은 책상 위. 훨씬 빠르지만 좁고, 전원 나가면 사라짐 |
| 프로비저닝(Provisioning) | 자원을 미리 정해서 할당해두는 것 | 식당에서 미리 자리 예약. 안 와도 자리값은 나감 |
| 서버리스(Serverless) | 서버를 내가 관리하지 않고, 쓴 만큼만 내는 방식 | 서버가 없다는 뜻이 아니라 내가 신경 안 쓴다는 뜻 |
!
그림 1. DB 선택 의사결정 트리
— "관계형인가? → 예: RDS/Aurora, 아니오: DynamoDB → 캐시가 필요한가? → ElastiCache/DAX"
형태의 플로우차트를 넣을 자리. draw.io 또는 Excalidraw로 제작 예정.
학교 프로젝트에서 MySQL을 직접 써봤다면 이런 일을 해봤을 것이다.
apt install mysql-server로 설치한다RDS는 3~6번을 AWS가 대신 해준다. 이게 "관리형"의 의미다.
지원 엔진은 6가지: MySQL, PostgreSQL, MariaDB, Oracle, SQL Server, Db2.
| AWS가 대신 해줌 ✅ | 여전히 내 몫 ❌ |
|---|---|
| 서버 프로비저닝, OS·DB 보안 패치 | 테이블 스키마 설계 |
| 자동 백업, 특정 시점 복구 | 느린 쿼리 튜닝, 인덱스 설계 |
| 모니터링 지표 수집 | 인스턴스 타입(크기) 선택 |
| 복제본·다중 AZ 구성 버튼 하나로 | DB 파라미터 튜닝 |
| — | SSH 접속 불가 (OS에 못 들어감) |
⚠️ 시험 함정 예시
"DB 서버에 로그 수집 에이전트를 직접 설치해야 한다. 어떻게 해야 하는가?"
→ RDS는 OS 접근이 막혀 있어서 불가능하다. 정답은 "EC2에 DB를 직접 설치(self-managed)"다.
RDS 문제에서 SSH, 커스텀 데몬 설치, OS 커널 설정 같은 말이 나오면 거의 함정이다.
그림 2. RDS 책임 공유 모델 — 하드웨어/OS/DB엔진/데이터를 계층으로 쌓고,
어디까지가 AWS 책임이고 어디부터가 사용자 책임인지 색으로 구분.
DB를 만들 때 "스토리지 20GB"처럼 용량을 정한다. 그런데 서비스가 잘 되면 데이터가 늘어난다.
디스크가 꽉 차면 DB는 그냥 멈춘다. 이걸 막아주는 기능이다.
동작 조건 (셋 다 만족해야 발동)
예시: 100GB 디스크에서 여유가 8GB로 떨어지고 5분이 지나면 → AWS가 자동으로 늘려준다.
Maximum Storage Threshold(최대 스토리지 임계값)를 설정해두면 무한정 늘어나는 걸 막을 수 있다.
버그로 로그가 폭주해서 디스크가 10TB까지 늘어나는 사고를 방지하는 안전장치다.
문제 상황: 쇼핑몰 DB 하나에 주문 처리(쓰기)와 마케팅팀 통계 쿼리(읽기)가 몰린다.
마케팅팀이 무거운 집계 쿼리를 돌릴 때마다 주문이 느려진다.
해결: 읽기 전용 복사본을 따로 만들어서, 통계 쿼리는 그쪽으로 보낸다.
💡 다른 리전 복제본 활용 예시
본사는 서울, 사용자 절반은 미국. 미국 리전에 읽기 복제본을 두면
미국 사용자의 조회 응답이 태평양을 왕복하지 않아 훨씬 빨라진다.
문제 상황: 서울 리전의 한 데이터센터(AZ)에 장애가 났다. 내 DB가 거기 있었다.
해결: 다른 AZ에 똑같은 DB를 하나 더 두고, 장애 시 자동으로 넘긴다.
⚠️ 가장 많이 나오는 함정
"읽기 성능이 부족하다. Multi-AZ를 켜면 되는가?"
→ 안 된다. 대기 인스턴스는 읽기를 안 받는다. 정답은 Read Replica.반대로 "AZ 장애에 대비해야 한다. Read Replica를 만들면 되는가?"
→ 자동 페일오버가 없으므로 부적합. 정답은 Multi-AZ.

그림 3. 좌측에 Read Replica(비동기·읽기 분산), 우측에 Multi-AZ(동기·페일오버) 구조를 나란히 배치.
SAA에서 가장 많이 헷갈리는 두 개념이므로 반드시 시각화할 것.
| 구분 | Read Replica | Multi-AZ | Multi-Region |
|---|---|---|---|
| 목적 | 읽기 확장 (성능) | 고가용성 (안정성) | 재해 복구 + 지연 감소 |
| 복제 | 비동기 (최종 일관성) | 동기 (강한 일관성) | 비동기 |
| 읽기 가능 | ✅ | ❌ (대기만 함) | ✅ |
| 자동 페일오버 | ❌ (수동 승격) | ✅ | ❌ |
| 앱 코드 수정 | 필요 (읽기 주소 분리) | 불필요 | 필요 |
💡 Multi-AZ DB Cluster: 대기 인스턴스를 2개 두면서 읽기까지 받을 수 있게 만든 신형 옵션.
"고가용성도 필요하고 읽기 성능도 필요하다"는 문제에서 정답이 될 수 있다.
기존 Multi-AZ(대기본이 놀고 있음)의 아쉬움을 보완한 버전이라고 이해하면 된다.
두 가지 방식이 있고, 시험은 보존 기간으로 둘을 구분한다.
① 자동 백업 (Automated Backup)
② 수동 스냅샷 (Manual Snapshot)
문제 상황: Lambda 함수가 요청마다 DB에 접속한다. 트래픽이 몰려 Lambda가 1,000개로 늘어나면
DB 커넥션도 1,000개가 열린다. MySQL의 기본 최대 커넥션은 훨씬 작아서 DB가 뻗는다.
이걸 커넥션 폭증(connection storm) 이라고 한다.
해결: 중간에 프록시를 두고 커넥션 풀(연결 재사용 창고) 을 관리한다.
🧪 내 논문 연결점: 서버리스 함수가 폭발적으로 스케일아웃될 때 DB 커넥션이 병목이 된다.
RDS Proxy는 이 "다대일 자원 경합"을 완충하는 계층이다.
오토스케일링이 컴퓨팅만 늘려도 하위 자원(커넥션)이 스케일되지 않으면 전체가 무너진다는
좋은 사례이기도 하다.
RDS는 기존 MySQL/PostgreSQL을 그대로 클라우드에 올린 것이다.
Aurora는 AWS가 스토리지 계층을 아예 새로 설계해서 만든 MySQL/PostgreSQL 호환 DB다.
"호환"이라는 말이 중요하다. 내부 구현은 완전히 다르지만
애플리케이션 입장에선 MySQL/PostgreSQL 드라이버를 그대로 쓸 수 있다.
Aurora의 모든 장점은 이 구조 하나에서 나온다. 핵심은 컴퓨팅과 스토리지의 분리다.
일반 DB는 서버 안에 디스크가 붙어 있다. Aurora는 DB 인스턴스(계산) 와
공유 스토리지 볼륨(저장) 이 분리돼 있고, 스토리지는 여러 서버에 흩어져 있다.
쿼럼(Quorum)이란?
여러 복사본 중 "몇 개가 동의하면 유효한 것으로 인정할지"를 정한 정족수다.
국회 의결정족수와 같은 개념이다. 전부의 동의를 기다리지 않아서 빠르고,
일부가 죽어도 진행되니까 튼튼하다.
Aurora의 규칙:
이 규칙에서 자동으로 따라 나오는 결론:
여기에 자가 복구(self-healing) 가 붙는다. 손상된 블록을 감지하면
다른 복제본에서 데이터를 가져와 알아서 고친다.

그림 4. Aurora 아키텍처 — 상단에 Writer 1개 + Reader N개,
하단에 3개 AZ에 걸친 공유 스토리지 볼륨(6개 복제본)을 그리고 화살표로 연결.
"컴퓨팅 ↔ 스토리지 분리"가 시각적으로 드러나야 함.
Aurora는 인스턴스가 여러 개(Writer 1개 + Reader N개)라서 접속 주소도 여러 종류다.
| 엔드포인트 | 역할 | 언제 쓰나 |
|---|---|---|
| Writer Endpoint | 항상 현재 마스터를 가리킴 | INSERT/UPDATE/DELETE |
| Reader Endpoint | 읽기 복제본들에 자동 분산 | SELECT |
| Custom Endpoint | 특정 인스턴스들만 묶어서 지정 | 분석 전용 대형 인스턴스 그룹 |
Writer Endpoint의 장점 예시: 마스터가 죽어서 복제본 하나가 승격돼도,
Writer Endpoint 주소는 그대로다. 애플리케이션은 아무것도 안 바꿔도 된다.
Custom Endpoint 활용 예시: 일반 API용 인스턴스는 db.r6g.large,
데이터 분석팀용은 db.r6g.8xlarge로 두고, 분석팀에게만 큰 인스턴스를 가리키는
커스텀 엔드포인트를 준다. 무거운 쿼리가 일반 사용자에게 영향을 주지 않는다.
⚠️ Reader Endpoint의 부하 분산은 연결(Connection) 단위이지 쿼리 단위가 아니다.
커넥션 풀을 쓰면 한 번 맺은 연결이 계속 유지되므로 분산이 고르지 않을 수 있다.
Replica Auto Scaling
읽기 부하(CPU 사용률 등)에 따라 복제본 개수를 자동으로 늘리고 줄인다. 최대 15개.
→ 예: 평소 2개, 이벤트 때 8개, 끝나면 다시 2개.
Global Database (글로벌 데이터베이스)
Backtrack (백트랙)
Database Cloning (클로닝)
Copy-on-Write란? 처음엔 데이터를 복사하지 않고 원본을 같이 바라보다가,
수정이 일어난 블록만 그때 복사하는 기법. 초기 복사 비용이 거의 0이다.
Aurora Machine Learning
SQL 함수 호출만으로 SageMaker나 Comprehend 모델을 호출한다.
예: SELECT sentiment(review_text) FROM reviews; 형태로 감성 분석 결과를 바로 얻는다.
ACU(Aurora Capacity Unit) 라는 단위로 용량을 표현한다.
1 ACU ≈ 2GiB 메모리 + 그에 상응하는 CPU/네트워크로 보면 된다.
예시: 대학 수강신청 시스템. 1년 중 나흘만 트래픽이 폭발하고 나머지는 거의 놀고 있다.
프로비저닝 방식이면 피크에 맞춰 큰 인스턴스를 1년 내내 켜둬야 하지만,
Serverless v2는 그 나흘에만 확 올라간다.
관계형 DB(RDS/Aurora)는 강력하지만 두 가지 한계가 있다.
ALTER TABLE을 해야 하고, 큰 테이블에선 위험하다DynamoDB는 수평 확장(Scale-Out) 을 기본으로 한다. 서버를 계속 추가해 나가는 방식이라
이론상 용량과 처리량에 한계가 없다. 대신 JOIN이 없다.
적합한 예시: 게임 사용자 프로필, 세션 데이터, IoT 센서 로그, 장바구니, 리더보드 원본 데이터
부적합한 예시: 여러 테이블을 JOIN해서 복잡한 집계를 내는 ERP, 회계 시스템
DynamoDB의 기본 키는 두 가지 형태다.
① 파티션 키만 (Simple Primary Key)
<Users 테이블
PK: user_id
"u1001" → { name: "김동민", grade: 4 }
"u1002" → { name: "이철수", grade: 2, club: "밴드부" } ← 속성이 달라도 됨
② 파티션 키 + 정렬 키 (Composite Primary Key)
<Orders 테이블
PK: user_id, SK: order_date
"u1001" / "2026-08-01" → { item: "키보드", price: 89000 }
"u1001" / "2026-08-03" → { item: "마우스", price: 35000 }
"u1001" / "2026-08-05" → { item: "모니터", price: 320000 }
이 구조면 "u1001의 8월 주문 전체를 최신순으로" 같은 범위 쿼리가 가능하다.
파티션 키가 하는 일: 값을 해시 함수에 넣어서 데이터가 어느 물리 파티션(서버)에 저장될지 결정한다.
그래서 파티션 키가 곧 데이터 분산의 기준이 된다.
⚠️ 핫 파티션(Hot Partition)
특정 파티션 키에만 요청이 쏠리면 그 파티션 하나가 과부하돼 스로틀링이 난다.나쁜 예: 파티션 키를
날짜로 잡은 로그 테이블.
오늘 들어오는 모든 로그가"2026-08-05"하나에 몰린다. 다른 파티션은 놀고 하나만 죽는다.좋은 예:
날짜#기기ID처럼 카디널리티(값의 종류 수)가 높은 키를 쓴다.
요청이 여러 파티션에 고르게 흩어진다.

그림 5. 파티션 키 해싱 → 여러 파티션으로 분산되는 구조.
잘 분산된 케이스와 핫 파티션 케이스를 좌우로 대비해서 그릴 것.
예시: 게시글 조회수는 결과적 일관성으로 충분하다. 잠깐 1 차이 나도 아무 문제없다.
반면 재고 수량 확인은 강력한 일관성이 필요하다. 재고가 0인데 1로 읽히면 초과 판매가 난다.
왜 필요한가: DynamoDB는 기본적으로 파티션 키로만 조회할 수 있다.
Users 테이블의 PK가 user_id인데 "이메일로 사용자 찾기"를 하려면?
전체를 훑는 Scan을 해야 하는데 이건 느리고 비싸다. 그래서 다른 키로 조회할 인덱스를 만든다.
| GSI (Global Secondary Index) | LSI (Local Secondary Index) | |
|---|---|---|
| 파티션 키 | 완전히 다른 속성 가능 | 테이블과 반드시 동일 |
| 정렬 키 | 자유롭게 지정 | 다르게 지정 |
| 생성 시점 | 언제든 추가/삭제 가능 | 테이블 생성 시에만 |
| 용량 | 자체 RCU/WCU를 따로 가짐 | 테이블 용량을 같이 씀 |
| 일관성 | 결과적 일관성만 | 강력한 일관성 지원 |
| 개수 제한 | 기본 20개 | 5개 |
| 크기 제한 | 없음 | 파티션 키당 10GB |
GSI 예시: Orders 테이블(PK: user_id)에 "상품별 주문 조회"가 필요해졌다.
→ PK를 product_id로 한 GSI를 만든다. 운영 중에도 추가 가능.
LSI 예시: Orders 테이블(PK: user_id, SK: order_date)에서
"금액순 정렬"도 필요하다 → PK는 그대로 user_id, SK만 price인 LSI.
단, 테이블 만들 때 같이 만들었어야 한다.
⚠️ 시험 함정: "이미 운영 중인 테이블에 새로운 조회 패턴이 필요해졌다"
→ LSI는 나중에 못 만든다 → 정답은 무조건 GSI.
DAX (DynamoDB Accelerator)
DynamoDB Streams
TTL (Time To Live)
expires_at = 지금+24시간. 하루 뒤 알아서 사라진다Global Tables
PITR / Transactions
| DAX | ElastiCache | |
|---|---|---|
| 캐싱 대상 | DynamoDB 쿼리 결과 전용 | 아무 데이터나 |
| 코드 변경 | 불필요 (드롭인) | 필요 (캐시 조회/저장 로직 직접 구현) |
| 적합 | 개별 항목 조회, Query/Scan 결과 | 집계 결과, 세션, 리더보드 |
문제에 "DynamoDB인데 코드 수정 없이 읽기를 더 빠르게"가 나오면 DAX다.
문제 상황: 쇼핑몰 메인 페이지가 "이번 주 인기 상품 TOP 10"을 보여준다.
이걸 계산하려면 주문 테이블 수백만 건을 집계해야 한다. 그런데 이 결과는 1분에 한 번 바뀌어도 충분하다.
사용자가 10,000명이면 같은 계산을 10,000번 반복하는 셈이다.
해결: 계산 결과를 메모리에 넣어두고 1분간 그냥 꺼내 쓴다. 이게 캐시다.
ElastiCache는 관리형 인메모리 데이터 스토어다. 지원 엔진은 3가지.
Valkey가 왜 생겼나: Redis가 2024년에 라이선스를 바꾸면서 커뮤니티가 포크했고,
Linux Foundation이 관리하는 프로젝트가 Valkey다. Redis와 API가 완전 호환이라
클라이언트 코드를 안 고치고 바꿔 끼울 수 있다.
캐시를 쓰는 이유는 크게 두 가지다.
1. DB 부하 감소 → 읽기 성능 향상 (그리고 DB 인스턴스를 줄일 수 있어 비용도 절감)
2. 애플리케이션을 무상태(Stateless)로 만들기
무상태란? 서버가 사용자별 정보를 자기 메모리에 안 들고 있는 상태.
세션을 EC2 메모리에 두면, 그 EC2가 죽거나 로드밸런서가 다른 서버로 보낼 때 로그인이 풀린다.
세션을 ElastiCache에 빼두면 어느 서버로 가도 로그인이 유지되고, 서버를 마음대로 늘렸다 줄일 수 있다.

그림 6. ELB → EC2(Auto Scaling) → ElastiCache(캐시 히트/미스 분기) → RDS 구조도.
Cache Hit 경로와 Cache Miss 경로를 다른 색 화살표로 구분.
| 전략 | 동작 | 장점 | 단점 |
|---|---|---|---|
| Lazy Loading (Cache-Aside) | 캐시에 없을 때만 DB 조회 → 캐시에 저장 | 실제 요청된 데이터만 캐싱 | 첫 요청은 느림, 오래된 데이터 가능 |
| Write Through | DB에 쓸 때마다 캐시도 같이 갱신 | 캐시가 항상 최신 | 쓰기 지연↑, 안 읽을 데이터도 캐싱 |
| TTL 만료 | 일정 시간 후 자동 삭제 | 관리가 단순 | TTL 값 설계가 필요 |
Lazy Loading 코드 흐름 (의사코드)
<data = cache.get(key)
if data is None: # 캐시 미스
data = db.query(...)
cache.set(key, data, ttl=60)
return data
캐시 미스(Cache Miss) = 캐시에 없어서 DB까지 갔다 오는 것
캐시 히트(Cache Hit) = 캐시에서 바로 나오는 것. 히트율이 높을수록 좋은 캐시다
실무에선 Lazy Loading + TTL 조합이 가장 흔하다.
Write Through 단독은 "한 번도 안 읽힐 데이터까지 캐시에 채우는" 낭비가 있다.
| 구분 | Redis / Valkey | Memcached |
|---|---|---|
| Multi-AZ + 자동 페일오버 | ✅ | ❌ |
| 읽기 복제본 | ✅ | ❌ |
| 데이터 영속성 | ✅ (AOF, 스냅샷) | ❌ (재시작하면 다 날아감) |
| 백업/복원 | ✅ | ❌ |
| 데이터 구조 | Set, Sorted Set, List, Hash 등 | 단순 키-값만 |
| 멀티스레드 | 부분 지원 | ✅ 멀티스레드 |
| 구조 | 샤딩 + 복제 | 순수 샤딩(분할)만 |
AOF(Append Only File)란? 캐시에 들어온 모든 쓰기 명령을 파일에 순서대로 기록해두는 방식.
서버가 재시작해도 이 파일을 재생하면 데이터가 복구된다. Memcached엔 이런 게 없다.
시험 판별법
| 항목 | RDS | Aurora | DynamoDB | ElastiCache |
|---|---|---|---|---|
| 유형 | 관계형 | 관계형 (클라우드 네이티브) | NoSQL (키-값/문서) | 인메모리 캐시 |
| 서버리스 | ❌ | ✅ (Serverless v2) | ✅ | ✅ (Serverless 모드) |
| 지연 시간 | 수 ms | 수 ms | 한 자릿수 ms | 마이크로초 ~ 1ms |
| 스토리지 | 최대 64TB | 10GB→128TB 자동 | 무제한 자동 | 메모리 크기까지 |
| 읽기 확장 | 복제본 5개 | 복제본 15개 | 자동 파티셔닝 | 복제본 (Redis/Valkey) |
| 다중 리전 | 리전 간 복제본 | Global Database (주 리전만 쓰기) | Global Tables (전 리전 쓰기) | Global Datastore |
| 스키마 | 고정 | 고정 | 유연 | N/A |
| JOIN | ✅ | ✅ | ❌ | ❌ |
| 주용도 | 기존 앱 마이그레이션 | 고성능/글로벌 관계형 | 대규모 서버리스 앱 | 캐시/세션 |

그림 7. 4개 서비스를 축(관계형↔비관계형 / 낮은지연↔높은처리량)에 배치한 2×2 매트릭스.
마지막 복습용 한 장 요약 이미지.
| 시나리오 | 정답 | 왜? |
|---|---|---|
| 분석 쿼리가 운영 DB 성능을 떨어뜨린다 | RDS Read Replica | 읽기를 분리하는 게 목적 |
| AZ 장애에도 DB가 살아 있어야 한다 | RDS Multi-AZ | 자동 페일오버가 필요 |
| 전 세계 읽기 지연 최소화 + 리전 장애 대비 (관계형) | Aurora Global Database | 복제 지연 1초 미만 |
| 여러 리전에서 동시에 쓰기가 필요하다 | DynamoDB Global Tables | 액티브-액티브는 여기만 |
| Lambda가 커넥션을 폭주시킨다 | RDS Proxy | 커넥션 풀링 |
| 운영 DB와 같은 테스트 환경을 빠르게 | Aurora Cloning | Copy-on-Write |
| 잘못된 배포로 데이터를 날렸다, 빨리 되돌려라 | Aurora Backtrack | 복원보다 훨씬 빠름 |
| 트래픽이 간헐적이고 유휴가 길다 (관계형) | Aurora Serverless v2 | 0 ACU까지 축소 |
| 서버리스 + 밀리초 + 단순 GET/PUT | DynamoDB | JOIN이 필요 없는 케이스 |
| DynamoDB 읽기를 코드 수정 없이 더 빠르게 | DAX | 드롭인 캐시 |
| DynamoDB 항목 변경 시 후속 처리가 필요 | DynamoDB Streams | Lambda 트리거 |
| 이미 운영 중인 테이블에 새 조회 패턴 추가 | GSI | LSI는 나중에 못 만듦 |
| 여러 EC2 간 세션 공유 | ElastiCache | 무상태 아키텍처 |
| 실시간 게임 순위표 | ElastiCache (Sorted Set) | 정렬 자료구조 필요 |
| RDS를 나중에 암호화해야 한다 | 스냅샷 → 암호화 복사 → 복원 | 생성 시에만 켤 수 있으므로 |
여기부터는 같은 아키텍처를 유지하면서 요금을 줄이는 방법이다.
SAA 도메인 4(비용 최적화)에서 직접 출제되는 영역이라 개념편과 분리해 정리했다.
클라우드 비용을 이해하는 첫 단계는 "무엇에 과금되는가(과금 축)" 를 아는 것이다.
축을 알아야 어디를 줄일지 판단할 수 있다.
| 서비스 | 과금 축 |
|---|---|
| RDS | 인스턴스 시간 + 스토리지 + 백업 + 데이터 전송 |
| Aurora | 인스턴스 시간(또는 ACU) + 스토리지 + I/O 요청 수 |
| DynamoDB | RCU/WCU(프로비저닝) 또는 요청 건당(온디맨드) + 스토리지 |
| ElastiCache | 노드 시간(노드 기반) 또는 GB-시간 + ECPU(서버리스) |
핵심 구분: 프로비저닝형 vs 사용량 기반
그래서 트래픽이 안정적이면 프로비저닝, 변동이 크면 사용량 기반이 유리하다.
이 교차점을 판단하는 게 비용 문제의 본질이다.

그림 8. x축 "트래픽 변동성 / 가동률", y축 "월 비용"으로 두고
프로비저닝형 vs 서버리스형의 비용 곡선이 교차하는 지점(손익분기점)을 표시.
① 개발/테스트 DB는 중지한다
스냅샷을 만들고 인스턴스를 중지하면 인스턴스 요금이 멈춘다.
(스토리지 요금은 계속 나가고, 최대 7일까지 중지 가능하다는 점은 주의)
→ 예: 팀 개발 DB를 퇴근 시간에 중지하는 Lambda 스케줄을 걸어둔다.
② 리전 간(Cross-Region) 복제본 주의
같은 리전 AZ 간 복제 트래픽은 무료지만, 리전 간 복제는 데이터 전송 요금이 붙는다.
"글로벌 서비스를 만들었는데 비용이 예상보다 크다" 유형의 문제에 자주 등장한다.
③ Reserved Instance (예약 인스턴스)
1년/3년 약정으로 큰 폭 할인. 상시 돌아가는 운영 DB에 적합하다.
→ 판단 기준: 1년 내내 켜둘 게 확실한가? 그렇다면 RI, 아니면 온디맨드.
④ 백업 보존 기간 조정
자동 백업 35일이 항상 정답은 아니다. 규제 요건이 없다면 7일로 줄여도 된다.
⑤ Graviton(ARM) 인스턴스 전환
같은 성능을 더 싸게 낸다. db.r6g, db.r7g 계열.
① Serverless v2 + scale-to-zero(0 ACU)
유휴가 긴 개발/스테이징 환경에서 "안 쓰는 시간의 요금"을 사실상 없앨 수 있다.
→ 예: 개발 DB를 프로비저닝 인스턴스로 켜두면 밤 12시간도 요금이 나가지만,
Serverless v2는 트래픽이 없으면 0 ACU로 내려간다.
② Database Savings Plans
Serverless v2와 DSQL은 Reserved Instance 대상이 아니다.
할인 경로가 Savings Plans뿐이라는 게 시험 포인트가 될 수 있다.
③ Cloning 활용
Copy-on-Write라 초기 스토리지 비용이 거의 안 든다.
1TB 운영 DB를 통째로 복사하는 것과 비교하면 차이가 크다.
④ I/O-Optimized 구성
Aurora 표준 구성은 I/O 요청 수에 따라 과금된다.
읽기·쓰기가 아주 많은 워크로드라면 I/O 요금이 따로 안 붙는 구성이 총액에서 더 쌀 수 있다.
→ 판단 기준: 전체 비용에서 I/O가 차지하는 비중이 대략 25%를 넘어가는지.
| 프로비저닝 모드 | 온디맨드 모드 | |
|---|---|---|
| 과금 | 확보한 RCU/WCU × 시간 | 실제 요청 건당 |
| 적합 | 예측 가능한 꾸준한 트래픽 | 예측 불가 / 급격한 스파이크 |
| 확장 | Auto Scaling을 따로 설정 | 즉시 자동 |
| 비용 | 안정적 부하에서 크게 저렴 | 유휴 시 0에 가까움 |
| 리스크 | 용량 초과 시 스로틀링 | 예상 못한 폭탄 요금 |
판단 예시
용량 단위(Capacity Unit) 는 DynamoDB의 처리량 화폐 단위다.
계산 예제 1 — 쓰기
3KB짜리 항목을 초당 100회 써야 한다.
3KB ÷ 1KB = 3 → 올림해서 3 WCU × 100회 = 300 WCU
계산 예제 2 — 강력한 일관된 읽기
8KB짜리 항목을 초당 50회 강력한 일관성으로 읽는다.
8KB ÷ 4KB = 2 → 2 RCU × 50회 = 100 RCU
계산 예제 3 — 결과적 일관된 읽기 (같은 조건)
결과적 일관성은 절반만 쓴다 → 100 ÷ 2 = 50 RCU
💡 핵심: 강력한 일관성은 RCU를 2배 먹는다.
"비용을 줄이려면?" 하는 문제에서 요구사항이 허용한다면 결과적 일관된 읽기가 정답.
① Valkey로 전환 — 사실상 무조건 이득
서버리스 기준 33%, 노드 기반 기준 20% 저렴하다.
Redis OSS와 API가 완전 호환이라 코드 수정 없이 무중단 전환이 된다.
예약 노드를 쓰고 있었다면 기존 할인율도 유지된다.
② 서버리스 진입 장벽이 낮아졌다
Valkey 서버리스는 최소 스토리지가 100MB(Redis OSS의 1/10)라
월 $6 수준부터 시작할 수 있다. 사이드 프로젝트나 소규모 서비스에 부담이 적다.
③ 서버리스 vs 노드 기반 — 어느 쪽이 싼가
ECPU란? ElastiCache Processing Unit. 서버리스 전용 처리량 단위다.
1KB 전송당 1 ECPU로 계산한다. 4KB짜리 GET 하나 = 4 ECPU.
SORT나 Lua 스크립트처럼 CPU를 더 쓰는 명령은 그만큼 더 소모한다.
④ 캐시 자체가 비용 절감 수단이다
캐시를 붙이면 DB 부하가 줄어서 RDS/Aurora 인스턴스 크기를 낮출 수 있다.
캐시 요금보다 줄어든 DB 요금이 더 큰 경우가 흔하다.
→ 문제에서 "성능은 유지하면서 DB 비용을 줄여라"가 나오면 캐시를 떠올릴 것.
| 시나리오 | 정답 |
|---|---|
| 개발 DB가 밤에는 안 쓰이는데 요금이 계속 나간다 | 스냅샷 후 인스턴스 중지 / Aurora Serverless v2 |
| 트래픽이 예측 불가해 용량 산정이 어렵다 | DynamoDB 온디맨드 |
| 안정적인 상시 트래픽인데 온디맨드 요금이 부담된다 | 프로비저닝 + Auto Scaling |
| DynamoDB 읽기 비용을 절반으로 줄이고 싶다 | 결과적 일관된 읽기로 전환 |
| 오래된 데이터가 쌓여 스토리지 비용이 는다 | DynamoDB TTL |
| 캐시 비용을 33% 줄이면서 코드는 그대로 두고 싶다 | Valkey로 전환 |
| DB 인스턴스를 키우지 않고 읽기 성능을 올리고 싶다 | ElastiCache / DAX / Read Replica |
| Serverless v2를 쓰는데 할인 옵션이 필요하다 | Database Savings Plans (RI 불가) |
| 1년 내내 켜둘 운영 DB의 요금을 줄이고 싶다 | Reserved Instance |