RDS Basics
분류: Layer 3 - AWS 인프라 & 보안
1. 한 줄 정의
섹션 제목: “1. 한 줄 정의”RDS(Relational Database Service)는 AWS에서 관계형 데이터베이스(MySQL, PostgreSQL 등)를 설치/관리 없이 바로 사용할 수 있게 해주는 관리형 서비스이다.
2. 왜 중요한가
섹션 제목: “2. 왜 중요한가”대부분의 서비스는 데이터를 DB에 저장한다. EC2에 직접 DB를 설치하면 백업, 패치, 스케일링을 모두 직접 해야 하지만, RDS는 이걸 자동으로 해준다.
3. 핵심 개념
섹션 제목: “3. 핵심 개념”지원하는 DB 엔진
MySQL, PostgreSQL, MariaDB, Oracle, SQL Server, Aurora(AWS 자체).
인스턴스 클래스
DB 서버의 성능(CPU, 메모리). db.t3.micro(소형) ~ db.r6g.16xlarge(대형).
Multi-AZ — 내부적으로 어떻게 동작하는가
비유: Multi-AZ는 “자동 전환 스위치가 달린 예비 발전기”이다. 평소에는 주 DB(Primary)만 쓰다가, 주 DB가 있는 AZ에 장애가 나면 예비 DB(Standby)로 자동 전환된다.
내부 동작:
- 주 DB(Primary)와 예비 DB(Standby)가 다른 가용영역(AZ)에 각각 존재
- 모든 쓰기 작업이 Primary → Standby로 동기식(Synchronous) 복제됨
- Primary 장애 감지 시 RDS가 DNS 레코드를 Standby의 IP로 자동 변경
- 애플리케이션은 Endpoint 주소가 동일하므로 재연결만 하면 됨
- 전환(Failover) 시간: 보통 60~120초
Endpoint가 하나인 이유: RDS는 DNS 이름으로 접속한다. Failover 시 DNS가 Standby를 가리키도록 바꾸기 때문에, 애플리케이션 코드는 변경 없이 재연결만 하면 된다.
📖 더 보기: AWS RDS Multi-AZ Failover 공식 문서 — Failover 트리거 조건과 소요 시간, 애플리케이션 재연결 처리 방법
Read Replica (읽기 복제본)
읽기 부하를 분산하기 위한 복제본. 쓰기는 주 DB에서, 읽기는 복제본에서 처리.
Multi-AZ(Standby)와 달리 Read Replica는 비동기 복제이고 별도의 Endpoint를 가진다. NestJS에서 TypeORM 설정으로 읽기/쓰기 DB를 분리할 수 있다.
// TypeORM 읽기/쓰기 분리 설정 예시TypeOrmModule.forRoot({ type: "postgres", replication: { master: { host: process.env.DB_MASTER_HOST, // RDS Primary Endpoint port: 5432, username: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_NAME, }, slaves: [ { host: process.env.DB_REPLICA_HOST, // Read Replica Endpoint port: 5432, username: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_NAME, }, ], },});// SELECT 쿼리는 자동으로 slave로, INSERT/UPDATE/DELETE는 master로 라우팅자동 백업 / 스냅샷
- 자동 백업: 매일 지정 시간에 백업. 최대 35일 보관.
- 수동 스냅샷: 원하는 시점에 직접 생성. 삭제 전까지 보관.
Parameter Group
DB 설정값을 묶어 RDS 인스턴스에 적용한다.
max_connections: DB가 허용하는 최대 동시 연결 수. 이 값을 초과하면 “too many connections” 에러 발생 → Connection Pool로 해결
Connection Pool (연결 풀) — 왜 필요한가
비유: DB 연결은 “전화 개통”과 같다. 매 요청마다 새로 개통하고 끊는 건 비용이 크다. Connection Pool은 미리 개통해둔 전화 회선을 재사용하는 것이다.
ECS + Fargate 환경에서 Connection Pool 계산법:
RDS max_connections ≥ (ECS Task 수) × (Pool max 설정값)
예) Task 10개 × Pool max 10 = 최대 100 연결 → RDS max_connections은 100 이상이어야 함 → db.t3.micro의 기본 max_connections은 약 90 → 부족!NestJS + TypeORM에서의 Connection Pool 설정:
TypeOrmModule.forRoot({ type: "postgres", host: process.env.DB_HOST, port: 5432, username: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_NAME, // Connection Pool 설정 extra: { max: 10, // 최대 연결 수 (RDS max_connections 초과 주의) min: 2, // 최소 유지 연결 수 idleTimeoutMillis: 30000, // 30초 이상 유휴 연결 제거 connectionTimeoutMillis: 5000, // 연결 대기 최대 5초 },});📖 더 보기: RDS Proxy를 이용한 Connection Pooling — RDS Proxy로 Failover 시간을 10초 이내로 줄이는 방법 (중급)
Endpoint (접속 주소)
RDS 인스턴스에는 고유한 접속 주소(Endpoint)가 부여된다.
예: mydb.xxxx.ap-northeast-2.rds.amazonaws.com:5432
애플리케이션의 DB 설정(환경변수 DATABASE_URL 등)에 이 주소를 입력한다. Multi-AZ를 사용해도 Endpoint는 하나로 유지되며, failover 시 AWS가 내부에서 라우팅을 바꿔준다.
⚠️ 보안 원칙: RDS는 반드시 Private Subnet에
RDS를 Public Subnet에 배치하면 인터넷에서 직접 접근이 가능해져 보안 위협이 된다.
반드시 Private Subnet에 두고, 같은 VPC 내의 애플리케이션(ECS/EC2)만 Security Group으로 접근을 허용해야 한다.
RDS Proxy — Connection Multiplexing과 Pinning
RDS Proxy는 애플리케이션과 RDS 사이에서 데이터베이스 연결을 대신 관리하는 완전 관리형 프록시 서비스다. 단순한 연결 풀링이 아니라 Connection Multiplexing이라는 개념으로 동작한다.
Connection Multiplexing 원리
애플리케이션(ECS Task)에서 RDS Proxy로 맺는 연결(프록시 연결)과, Proxy가 실제 RDS로 맺는 연결(백엔드 연결)을 분리한다. 100개의 ECS Task가 각자 Proxy에 연결되어 있어도, Proxy는 실제 RDS에는 10~20개의 연결만 유지하며 이를 여러 Task가 공유한다. 쿼리가 끝난 연결을 재사용하여 RDS에 도달하는 실제 연결 수를 획기적으로 줄인다. 이 덕분에 ECS Task 수가 급증해도 “too many connections” 에러 없이 안정적으로 동작한다.
[기존 방식]ECS Task 100개 × Pool max 5 = RDS 연결 500개 필요
[RDS Proxy 사용]ECS Task 100개 → Proxy 연결 100개Proxy → RDS 실제 연결 20개 (Multiplexing)→ RDS max_connections 부담이 1/5로 감소Pinning — Multiplexing이 비활성화되는 경우
Proxy는 기본적으로 연결을 공유(Multiplex)하지만, 특정 상황에서는 하나의 클라이언트 연결이 특정 백엔드 연결에 고정(Pin)된다. 고정된 동안은 다른 Task가 그 백엔드 연결을 사용할 수 없어 Multiplexing 효율이 떨어진다.
Pinning이 발생하는 주요 상황:
SET명령으로 세션 변수 설정 (SET @user_id = 1,SET NAMES utf8mb4등)- 임시 테이블(
CREATE TEMPORARY TABLE) 사용 - 사용자 잠금(
GET_LOCK()) 사용 - 멀티 스테이트먼트 실행 (
query1; query2;한 번에 전송) - 트랜잭션 내에서
SET autocommit=0사용
Pinning을 최소화하려면 세션 변수 사용을 줄이고, TypeORM의 기본 설정(준비된 구문 사용, 트랜잭션 명시적 관리)을 유지하는 것이 좋다. AWS 콘솔에서 RDS Proxy의 DatabaseConnectionsCurrentlySessionPinned 메트릭을 모니터링하면 Pinning 빈도를 확인할 수 있다.
RDS 비용 최적화 — 실무에서 적용 가능한 전략
-
인스턴스 Right-Sizing
CPU 사용률이 30% 미만, I/O가 지속적으로 낮다면 더 작은 인스턴스 클래스로 다운사이징한다. CloudWatch에서
CPUUtilization과ReadIOPS/WriteIOPS메트릭을 2주 이상 관찰 후 판단한다. -
Reserved Instance (예약 인스턴스)
프로덕션 DB처럼 상시 실행되는 RDS는 1년 또는 3년 약정 Reserved Instance로 전환하면 최대 72% 절감된다.
-
비 프로덕션 환경 자동 시작/중지
개발/스테이징 DB는 업무 시간 외에 자동 중지한다. AWS Instance Scheduler를 사용하면 평일 09:00
22:00만 실행하도록 자동화할 수 있어 비용을 6070% 절감할 수 있다.Terminal window # AWS CLI로 RDS 중지 (최대 7일, 이후 자동 재시작)aws rds stop-db-instance --db-instance-identifier my-dev-db# 예상 출력: DB instance status: stopping → stopped -
Aurora Serverless v2 고려
트래픽 패턴이 불규칙하거나 간헐적으로 사용하는 DB라면, Aurora Serverless v2는 사용량에 따라 자동 스케일업/다운되어 낭비 없이 사용할 수 있다.
-
스토리지 최적화 (gp2 → gp3 전환)
기존 gp2 스토리지를 gp3로 전환하면 동일 성능에서 약 20% 비용이 절감된다. 콘솔에서 스토리지 타입을 수정하면 다운타임 없이 전환 가능하다.
CloudWatch Database Insights — 성능 모니터링의 진화 (2025)
AWS는 기존 Performance Insights를 CloudWatch Database Insights로 통합했다 (2025년 말 기준 Performance Insights 콘솔 종료 예정). 실무에서 슬로우 쿼리를 찾을 때 이 도구를 사용한다.
경로: CloudWatch → Database Insights → <RDS 인스턴스>주요 기능:- DB Load: 현재 DB 부하를 Wait Event별로 분류 (CPU, I/O Wait, Lock Wait 등)- Top SQL: 가장 많은 부하를 유발하는 쿼리 순위- Execution Plan: 느린 쿼리의 실행 계획 분석 (Advanced 모드)3.5 RDS 원리의 전이 가능성 — 다른 도메인에서도 동일하게 나타나는 패턴
섹션 제목: “3.5 RDS 원리의 전이 가능성 — 다른 도메인에서도 동일하게 나타나는 패턴”RDS에서 배운 복제·연결 원리는 다른 분산 시스템에도 동일하게 적용된다. 패턴을 인식하면 낯선 기술도 빠르게 이해할 수 있다.
복제 원리 대응표
섹션 제목: “복제 원리 대응표”| RDS 개념 | 원리 | 다른 도메인의 동일 패턴 |
|---|---|---|
| Multi-AZ (동기 복제) | Primary 커밋 후 Standby 확인 응답까지 기다림 → 데이터 손실 0, 지연 증가 | Kafka ISR(In-Sync Replica): Producer가 acks=all로 쓰면 모든 ISR Broker가 수신 확인 후 커밋 / SQS FIFO: 메시지가 모든 AZ에 기록된 후 수신 확인 |
| Read Replica (비동기 복제) | Primary가 먼저 커밋 → Replica에 비동기 전파 → 복제 지연(Lag) 발생 가능 | CDN Edge 캐시: Origin에서 콘텐츠 변경 후 Edge 노드에 비동기 전파 → Edge TTL 동안 구버전 제공 (Stale Content) / Kafka 일반 복제 (acks=1): Leader 수신 후 Follower에 비동기 전파 |
| RDS Proxy Connection Multiplexing | 클라이언트 100개 연결 → Proxy → 실제 DB 연결 20개 (공유) | HTTP/2 Stream Multiplexing: 단일 TCP 연결 위에 여러 요청(Stream)을 동시 처리, 연결 생성 오버헤드 제거 / gRPC Channel: 하나의 HTTP/2 연결(Channel) 위에 여러 RPC 호출을 동시 다중화 |
왜 이 패턴이 반복되는가
섹션 제목: “왜 이 패턴이 반복되는가”동기 복제는 일관성(Consistency)을 보장하지만 지연이 생긴다. 비동기 복제는 성능을 높이지만 짧은 시간 동안 데이터 불일치가 허용된다. Multiplexing은 연결 수립 비용(TCP Handshake, TLS 협상)을 분산하여 처리량을 늘린다. 이 트레이드오프는 CAP 정리와 직결되며, 어느 시스템에서도 동일하게 나타난다.
📖 참고: gRPC on HTTP/2 — Engineering a Robust, High-performance Protocol — gRPC가 HTTP/2 단일 연결 위에서 멀티플렉싱하는 원리 공식 설명
3.6 RDS vs NoSQL — 언제 DynamoDB/MongoDB가 더 나은가
섹션 제목: “3.6 RDS vs NoSQL — 언제 DynamoDB/MongoDB가 더 나은가”RDS(관계형 DB)가 모든 워크로드에 최선은 아니다. 아래 기준으로 선택한다.
선택 기준 표
섹션 제목: “선택 기준 표”| 판단 기준 | RDS 선택 | DynamoDB/MongoDB 선택 |
|---|---|---|
| 트랜잭션 필요성 | ACID 트랜잭션 필수 (주문·결제·재고 차감) | 단순 조회/저장, eventual consistency 허용 |
| 쿼리 복잡도 | 다중 테이블 JOIN, GROUP BY, 집계 쿼리 | 단일 키/인덱스 기반 조회, 복잡한 JOIN 없음 |
| 스키마 유연성 | 스키마가 고정적이고 정규화가 중요한 경우 | 필드가 자주 추가/변경되거나 반정형(JSON) 데이터 |
| 수평 확장 요구 | 수백 GB ~ 수 TB, 연결 수 예측 가능 | 수 TB 이상, 초당 수만 건 쓰기, 자동 샤딩 필요 |
| 응답 지연 요구 | 수십 ms 허용 가능 | 한 자릿수 ms(게임 세션, 실시간 피드) |
Multi-AZ 도입 임계값
섹션 제목: “Multi-AZ 도입 임계값”Multi-AZ는 RDS 비용을 약 2배로 올린다(Standby 인스턴스 추가). 다음 조건을 모두 충족할 때 투자를 정당화할 수 있다.
- 서비스 다운타임 1시간당 비용 > Multi-AZ 월 추가 비용
- SLA 요구사항이 99.9% 이상 (월 허용 다운타임 약 44분)
- DB 장애 시 수동 복구 비용(엔지니어 공수)이 크거나 야간 장애 대응이 어려운 환경
개발/스테이징 환경에서는 Multi-AZ를 끄는 것이 일반적이다.
4. 실무에서 어디에 쓰이나
섹션 제목: “4. 실무에서 어디에 쓰이나”- 서비스의 주 데이터 저장소
- 읽기 부하가 많은 서비스에서 Read Replica 활용
- 장애 대비를 위한 Multi-AZ 구성
- DB 마이그레이션 시 스냅샷 활용
5. 현재 내 업무와 연결점
섹션 제목: “5. 현재 내 업무와 연결점”- 서비스의 DB 구조를 이해해야 데이터 흐름을 파악할 수 있음
- DB 관련 장애(connection timeout, slow query 등) 대응 시 RDS 설정 확인
- 배포 시 DB 마이그레이션이 포함될 때 RDS 동작 이해 필요
6. 자주 헷갈리는 개념 비교
섹션 제목: “6. 자주 헷갈리는 개념 비교”| 개념 A | 개념 B | 차이점 |
|---|---|---|
| RDS | EC2에 직접 DB 설치 | RDS는 백업/패치/failover 자동화, 직접 설치는 모두 수동 |
| Multi-AZ | Read Replica | Multi-AZ는 장애 대비(대기 DB), Read Replica는 읽기 부하 분산 |
| Aurora | RDS MySQL | Aurora는 AWS 자체 엔진으로 성능/가용성이 더 높지만 비용도 더 높음 |
| 자동 백업 | 스냅샷 | 자동 백업은 보관 기간 후 삭제, 스냅샷은 수동 삭제 전까지 유지 |
| Multi-AZ Standby | Read Replica | Standby는 Failover용(동기 복제, 별도 Endpoint 없음), Replica는 읽기 분산용(비동기 복제, 별도 Endpoint) |
6.5 트러블슈팅
섹션 제목: “6.5 트러블슈팅”🔧 Read Replica Stale Read — 오래된 데이터가 에러 없이 반환되는 경우
섹션 제목: “🔧 Read Replica Stale Read — 오래된 데이터가 에러 없이 반환되는 경우”증상: Read Replica에서 데이터를 읽었는데, 방금 Primary에 쓴 데이터가 조회되지 않음. 에러는 발생하지 않는다. 사용자가 정보를 수정했는데 화면에 이전 값이 보이거나, 재고를 차감했는데 읽기 복제본에서 여전히 이전 재고가 조회되는 상황.
원인: Read Replica는 비동기 복제로 동작한다. Primary에 쓰기가 완료된 직후에는 Replica에 반영되지 않을 수 있다. ReplicaLag(복제 지연)이 0이 아닌 상태에서 Replica를 읽으면 오래된 데이터가 반환되며, DB 드라이버나 ORM은 이를 에러로 처리하지 않는다.
ReplicaLag 메트릭 의미:
ReplicaLag = 0 → Replica가 Primary와 동기화됨 (최신 데이터)ReplicaLag = 5 → Replica가 Primary보다 5초 뒤처짐ReplicaLag = -1 → 복제가 비활성 상태모니터링 및 알람 설정:
# CloudWatch에서 ReplicaLag 확인 (AWS CLI)aws cloudwatch get-metric-statistics \ --namespace AWS/RDS \ --metric-name ReplicaLag \ --dimensions Name=DBInstanceIdentifier,Value=my-read-replica \ --start-time $(date -u -v-1H +%Y-%m-%dT%H:%M:%SZ) \ --end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \ --period 60 \ --statistics Average,Maximum
# CloudWatch 알람 설정 (ReplicaLag > 30초 시 SNS 알림)aws cloudwatch put-metric-alarm \ --alarm-name rds-replica-lag-high \ --metric-name ReplicaLag \ --namespace AWS/RDS \ --dimensions Name=DBInstanceIdentifier,Value=my-read-replica \ --statistic Average \ --period 60 \ --threshold 30 \ --comparison-operator GreaterThanThreshold \ --evaluation-periods 2 \ --alarm-actions arn:aws:sns:ap-northeast-2:123456789:alert-topic해결 전략:
| 상황 | 전략 |
|---|---|
| 쓰기 직후 즉시 읽어야 하는 경우 | TypeORM에서 해당 쿼리만 master(Primary) 연결로 라우팅 |
| 최종 일관성 허용 가능한 경우 | ReplicaLag 알람으로 지연이 임계값 초과 시 알림만 받음 |
| 재고·잔액 등 정확도가 중요한 경우 | 해당 엔티티 조회는 항상 Primary에서 수행 |
// TypeORM에서 특정 쿼리를 Primary로 강제 라우팅 (NestJS)// replication 설정이 있어도 { replicationMode: 'master' }로 Primary 강제 사용const result = await this.dataSource .createQueryBuilder(Order, "order") .setQueryRunner(await this.dataSource.createQueryRunner()) // master connection .where("order.id = :id", { id: orderId }) .getOne();📖 참고: AWS RDS Read Replica 모니터링 공식 문서 — ReplicaLag 메트릭 정의, DB 엔진별 측정 방법, CloudWatch 알람 설정
🔧 “too many connections” — DB 연결 수 초과
섹션 제목: “🔧 “too many connections” — DB 연결 수 초과”증상: 애플리케이션 로그에 FATAL: remaining connection slots are reserved for non-replication superuser connections 또는 too many connections 에러. 서비스 배포 시 또는 트래픽 급증 시 발생
원인: RDS Parameter Group의 max_connections 값보다 애플리케이션 전체 연결 수(ECS Task 수 × Connection Pool 크기)가 더 많음
해결:
- AWS 콘솔 → RDS → Monitoring →
DatabaseConnections메트릭으로 현재 연결 수 확인 ECS Task 수 × Pool max계산 (예: 10개 Task × Pool 10 = 최대 100 연결)- RDS
max_connections확인: Parameter Group →max_connections - 단기 해결: TypeORM
extra.max값 축소 - 근본 해결: RDS Proxy 도입으로 연결 다중화
🔧 “Connection timeout” — DB에 아예 연결 불가
섹션 제목: “🔧 “Connection timeout” — DB에 아예 연결 불가”증상: 서버 시작 시 또는 요청 처리 시 Connection timeout 또는 ECONNREFUSED 에러. 로컬에서는 되는데 서버에서만 안 됨
원인 1: RDS Security Group에서 ECS Task의 Security Group을 인바운드 허용하지 않음
원인 2: ECS Task가 RDS와 다른 VPC 또는 RDS에 접근할 수 없는 Subnet에 위치
해결:
- RDS Security Group → 인바운드 규칙 확인: ECS Task SG가 5432(PostgreSQL) 또는 3306(MySQL) 포트로 허용되어 있는지 확인
- ECS Task가 Private Subnet에 있고 NAT Gateway가 올바르게 설정되어 있는지 확인
DATABASE_URL환경변수의 Endpoint 주소가 정확한지 확인
🔧 Failover 후 애플리케이션이 DB를 못 찾는 경우
섹션 제목: “🔧 Failover 후 애플리케이션이 DB를 못 찾는 경우”증상: Multi-AZ Failover 발생 후 1~2분 동안 DB 관련 요청이 전부 실패. 이후에도 일부 프로세스에서 계속 연결 실패
원인: Connection Pool에 캐시된 옛 IP 주소를 계속 사용하거나, DNS TTL이 만료되지 않아 이전 Primary IP를 바라봄
해결:
- TypeORM 설정에
connectTimeoutMS및 재시도 로직 추가 - RDS Proxy를 사용하면 Failover 시 애플리케이션 단에서 별도 처리 없이 10초 이내 복구 가능
🔧 슬로우 쿼리로 인한 서비스 응답 지연
섹션 제목: “🔧 슬로우 쿼리로 인한 서비스 응답 지연”증상: 특정 API 엔드포인트에서 응답이 5초 이상 걸림. RDS의 CPUUtilization이 갑자기 높아짐
원인: 인덱스 누락, 대량 조회(풀 테이블 스캔), 또는 N+1 쿼리 문제
해결:
1. CloudWatch Database Insights → Top SQL 탭에서 오래 걸리는 쿼리 식별2. 해당 쿼리에 EXPLAIN 실행: EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 123; → Seq Scan(풀 스캔)이 나오면 인덱스 추가 필요
3. NestJS TypeORM에서 슬로우 쿼리 로깅 활성화: TypeOrmModule.forRoot({ logging: ["query", "slow"], // slow: 1초 이상 쿼리 로깅 maxQueryExecutionTime: 1000, // 1초 초과 시 SLOW QUERY 로그 })🔧 RDS 스토리지 자동 증가로 비용이 폭증한 경우
섹션 제목: “🔧 RDS 스토리지 자동 증가로 비용이 폭증한 경우”증상: RDS 비용이 예상보다 많이 나옴. AWS Cost Explorer에서 RDS 스토리지 항목이 크게 증가
원인: Storage Auto Scaling 기능이 켜져 있어 DB 데이터 증가 시 스토리지가 자동 확장됨. 확장된 스토리지는 축소되지 않음
해결:
# 현재 RDS 인스턴스의 스토리지 크기 및 Auto Scaling 설정 확인aws rds describe-db-instances \ --db-instance-identifier my-rds \ --query 'DBInstances[0].{AllocatedStorage:AllocatedStorage,MaxAllocatedStorage:MaxAllocatedStorage}'# 예상 출력:# {# "AllocatedStorage": 200, ← 현재 할당된 스토리지 (GB)# "MaxAllocatedStorage": 1000 ← Auto Scaling 최대치# }
# 불필요한 데이터 정리 후 스냅샷에서 더 작은 인스턴스로 복원하는 방법이 유일한 용량 축소 방법# 예방: Auto Scaling 최대치를 적절하게 설정 (기본값이 너무 크면 주의)aws rds modify-db-instance \ --db-instance-identifier my-rds \ --max-allocated-storage 100 # 최대 100GB로 제한7. 체크리스트
섹션 제목: “7. 체크리스트”- RDS가 뭔지, 왜 EC2에 직접 DB를 안 설치하는지 설명할 수 있다
- Multi-AZ와 Read Replica의 차이를 설명할 수 있다
- 팀 서비스가 어떤 DB 엔진을 사용하는지 안다
- DB 접속이 안 될 때 확인할 항목을 말할 수 있다 (SG, Subnet, Parameter Group, Connection Pool)
- “too many connections” 에러가 왜 발생하는지, Connection Pool로 어떻게 해결하는지 설명할 수 있다
8. 추가 학습 키워드
섹션 제목: “8. 추가 학습 키워드”Aurora Serverless, RDS Proxy, Performance Insights, Slow Query Log, Connection Pooling, DB Migration(DMS), CloudWatch Database Insights
📚 추천 리소스
섹션 제목: “📚 추천 리소스”- 📖 AWS RDS Multi-AZ Failover 공식 문서 — Failover 트리거 조건, DNS 전환 메커니즘, 소요 시간 공식 설명 (입문)
- 📖 RDS Proxy로 Connection Pooling 개선 — RDS Proxy 동작 원리와 Failover 단축 효과 AWS 블로그 (중급)
- 📖 AWS RDS Too Many Connections 해결 — max_connections 초과 에러 원인과 해결 방법 AWS re:Post (입문)
- 📖 NestJS TypeORM PostgreSQL 연결 가이드 — NestJS에서 TypeORM으로 RDS PostgreSQL 연결 설정 (입문)
- 📖 AWS RDS 비용 최적화 전략 2025 — Right-Sizing, Reserved Instance, Auto Scaling 비용 관리 실전 가이드 (중급)
- 📖 AWS RDS Read Replica 모니터링 — ReplicaLag 메트릭 정의, DB 엔진별 측정 방법, 복제 상태 모니터링 (중급)
- 📖 RDS vs DynamoDB 선택 가이드 — 워크로드 패턴별 DB 선택 기준 AWS 공식 가이드 (입문)
- 📖 gRPC on HTTP/2 — Multiplexing 원리 — gRPC Channel이 HTTP/2 단일 연결 위에서 멀티플렉싱하는 원리 공식 설명 (중급)
9. 내가 직접 확인해볼 것
섹션 제목: “9. 내가 직접 확인해볼 것”-
AWS 콘솔에서 팀 RDS 인스턴스 확인 (엔진, 인스턴스 클래스, Multi-AZ 여부)
경로: RDS → Databases → <인스턴스 이름>확인: DB engine, Instance class, Multi-AZ (Yes/No), Status (available) -
RDS의 Security Group 확인 (어디서 접속 허용인지)
경로: RDS → <인스턴스> → Connectivity & security → Security groups 클릭확인: Inbound rules에 ECS 또는 EC2의 SG가 DB 포트(5432/3306)로 허용되어 있는지 -
RDS 모니터링 탭에서 CPU/연결수/IOPS 확인
경로: RDS → <인스턴스> → Monitoring 탭주요 메트릭: DatabaseConnections (현재 연결 수), CPUUtilization, FreeStorageSpace예상 출력 (CloudWatch 그래프): DatabaseConnections가 평균 30~50 수준이면 정상 -
자동 백업 설정과 보관 기간 확인
-
psql 클라이언트로 직접 접속 테스트 (로컬 또는 Bastion에서)
Terminal window # PostgreSQL 직접 접속 테스트psql -h mydb.xxxx.ap-northeast-2.rds.amazonaws.com \-p 5432 \-U myuser \-d mydb# 패스워드 입력 후 연결 성공 시:# psql (14.10)# SSL connection (protocol: TLSv1.3, ...)# Type "help" for help.# mydb=># 연결 실패 시 (타임아웃):# psql: error: connection to server at "mydb.xxxx.ap-northeast-2.rds.amazonaws.com" (10.0.21.5),# port 5432 failed: Connection timed out# → Security Group 또는 NAT Gateway 설정 확인
10. 5줄 요약
섹션 제목: “10. 5줄 요약”- RDS는 백업·패치·Failover를 AWS가 자동 처리해주는 관리형 DB 서비스이다 — EC2에 직접 설치하면 이 모든 것을 직접 해야 한다
- Multi-AZ(장애 대비, 동기 복제, 자동 Failover)와 Read Replica(읽기 부하 분산, 비동기 복제)는 목적이 다르며 함께 쓸 수 있다
- DB 접속 문제의 체크리스트는 항상 동일하다: Security Group → Subnet/NAT → Endpoint 주소 → Connection Pool 크기 순서로 확인
- Connection Pool을 쓰더라도
ECS Task 수 × Pool 최대값이max_connections을 초과하면 “too many connections” 에러가 난다 — RDS Proxy로 근본 해결 가능 - 슬로우 쿼리가 발생하면 CloudWatch Database Insights(구 Performance Insights)에서 Top SQL을 찾고,
EXPLAIN ANALYZE로 인덱스 여부를 확인한다
프론트엔드 → 플랫폼 브릿지
섹션 제목: “프론트엔드 → 플랫폼 브릿지”프론트에서 DB를 “직접” 다룬다는 것의 위험성 이해
React + Firebase Realtime Database나 Supabase를 써봤다면, 클라이언트에서 직접 DB 쿼리를 날리는 경험이 있을 것이다. 편리하지만 그 뒤에는 Firebase/Supabase가 인증, 권한, 보안 규칙을 처리해주고 있다.
AWS RDS는 클라이언트(브라우저)에서 직접 접근이 구조적으로 불가능하다:
Firebase/Supabase 방식:브라우저 → Firebase SDK → DB (인증/권한은 Firebase가 처리)
AWS RDS 방식 (이 구조를 직접 제어):브라우저 → NestJS API (인증/비즈니스 로직) → RDS (Private Subnet) ↑ 인터넷에서 직접 접근 불가RDS는 Private Subnet에 있어서 인터넷에서는 아예 주소도 찾을 수 없다. 이것이 “보안 설계”다.
DB 연결 에러 — 로컬 vs 서버 환경 차이 이해
로컬에서는 DB 연결이 되는데 서버(ECS)에서는 안 되는 상황:
로컬 개발 환경:개발자 PC → (직접 RDS 접속 허용 필요) → 이유: PC의 IP가 Security Group에 허용되어 있을 때만 가능 → 실무에서는 로컬 → Bastion Host → RDS 경유가 일반적
ECS 서버 환경:ECS Task (Private Subnet, SG: sg-ecs-task) → RDS (SG: sg-rds) → RDS SG의 인바운드에 sg-ecs-task가 5432 허용되어 있어야 함 → 환경변수 DB_HOST가 RDS Endpoint인지 확인
흔한 실수: DB_HOST=localhost (로컬 DB 주소를 그대로 배포한 경우) DB_HOST=<잘못된 Endpoint> (dev DB Endpoint가 prod에 들어간 경우)실무 아키텍처 패턴 — RDS 프로덕션 구성
섹션 제목: “실무 아키텍처 패턴 — RDS 프로덕션 구성”[일반적인 프로덕션 RDS 아키텍처]
ECS Task (Private Subnet) └─ RDS Proxy (Connection Pooling + Failover 10초 이내) └─ RDS Primary (Private Subnet, Multi-AZ) └─ RDS Standby (다른 AZ, 자동 Failover)
[읽기 부하 분산이 필요한 경우]ECS Task ├─ TypeORM master → RDS Primary (쓰기) └─ TypeORM slave → Read Replica (읽기)
[개발/스테이징 환경]Aurora Serverless v2 — 트래픽 없을 때 자동 scale to zero, 비용 최소화2025년 업데이트 — Aurora Blue/Green 배포 (Global Database 지원): 2025년 11월부터 Aurora Global Database에서도 Blue/Green 배포가 지원된다. 스테이징 환경(Green)에서 메이저 버전 업그레이드, 스키마 변경, 파라미터 수정을 테스트한 후 짧은 다운타임만으로 프로덕션(Blue)에 적용할 수 있다.
2025년 업데이트 — Aurora 최대 스토리지 256TiB로 확장: Aurora의 최대 스토리지 용량이 기존 128TiB에서 256TiB로 두 배 늘어났다. Aurora MySQL 3.10 (MySQL 8.0.42 호환) 이상 버전에서 사용 가능하다.