2026. 6. 1. 07:14ㆍCloud/AWS
"EC2 하나에 웹 서버, 애플리케이션, 데이터베이스를 모두 올려서 운영하고 있습니다. 트래픽이 늘면 어떻게 확장하죠?" — 이 질문에 대한 답이 3-Tier 아키텍처입니다.
핵심 요약
- 3-Tier 아키텍처는 Web(프레젠테이션), App(비즈니스 로직), DB(데이터) 계층을 분리하여 각 계층을 독립적으로 확장하고 보호하는 설계 패턴입니다.
- AWS에서는 ALB + Auto Scaling Group + RDS Multi-AZ 조합이 가장 일반적인 구현 방식입니다.
- 각 계층을 별도 Subnet에 배치하고, Security Group으로 계층 간 통신만 허용하는 것이 보안 설계의 핵심입니다.
- 단일 인스턴스 구성 대비 비용은 증가하지만, 장애 격리, 독립 확장, 보안 강화라는 운영 이점을 얻습니다.
- 모든 설계 선택에는 trade-off가 있으며, 서비스 규모와 요구사항에 따라 구성을 조정해야 합니다.
1. 설계 배경과 시나리오
1.1 시나리오: 스타트업 B2B SaaS 서비스
월간 활성 사용자 5,000명 규모의 B2B SaaS 서비스를 운영한다고 가정합니다.
현재 상태: - EC2 1대에 Nginx + Spring Boot + PostgreSQL을 모두 설치 - 트래픽 증가 시 수직 확장(인스턴스 타입 변경)으로 대응 - DB 백업은 수동으로 진행
문제점: - 애플리케이션 배포 시 전체 서비스 중단 - DB 장애 시 복구까지 수 시간 소요 - 트래픽 급증 시 단일 인스턴스 한계로 서비스 지연 - 웹 서버 취약점이 DB까지 직접 영향을 줄 수 있음
1.2 설계 목표
| 항목 | 요구사항 |
|---|---|
| 가용성 | 단일 AZ 장애 시에도 서비스 유지 |
| 확장성 | 트래픽 증가 시 App 계층 수평 확장 |
| 보안 | 계층 간 최소 권한 통신, DB 인터넷 노출 차단 |
| 배포 | 무중단 배포 가능한 구조 |
| 비용 | 월 $500~$1,000 범위 내 운영 |
1.3 왜 3-Tier인가
단일 서버 구성과 3-Tier 구성의 차이를 정리합니다.
| 기준 | 단일 서버 | 3-Tier |
|---|---|---|
| 장애 영향 범위 | 전체 서비스 중단 | 해당 계층만 영향 |
| 확장 방식 | 수직 확장만 가능 | 계층별 수평 확장 |
| 보안 격리 | 불가능 | 계층별 네트워크 분리 |
| 배포 | 전체 재시작 필요 | 계층별 독립 배포 |
| 비용 | 낮음 (초기) | 높음 (인프라 분리 비용) |
| 운영 복잡도 | 낮음 | 중간~높음 |
트래픽이 적고 장애 허용 범위가 넓은 초기 단계에서는 단일 서버가 합리적일 수 있습니다. 다만 서비스가 성장하면서 가용성, 보안, 확장성 요구가 높아지면 계층 분리가 필요합니다.
2. 전체 아키텍처 구조
3-Tier 아키텍처의 전체 구조는 다음과 같습니다.
Web Tier (Public Subnet) - ALB(Application Load Balancer)가 인터넷 트래픽을 수신 - 사용자 요청을 App Tier로 분배 - HTTPS 종료(TLS Termination) 처리
App Tier (Private Subnet) - Auto Scaling Group으로 EC2 인스턴스 관리 - 비즈니스 로직 처리 (Spring Boot, Node.js 등) - 외부 인터넷 접근 시 NAT Gateway 경유
DB Tier (Private Subnet) - RDS Multi-AZ로 고가용성 확보 - App Tier에서만 접근 가능 - 자동 백업, 스냅샷, 장애 조치(Failover) 지원
3. 네트워크 설계
3.1 VPC와 Subnet 구성
VPC CIDR: 10.0.0.0/16 (65,536 IP)
Public Subnet (Web Tier):
- AZ-a: 10.0.1.0/24 (256 IP)
- AZ-c: 10.0.2.0/24 (256 IP)
Private Subnet (App Tier):
- AZ-a: 10.0.11.0/24 (256 IP)
- AZ-c: 10.0.12.0/24 (256 IP)
Private Subnet (DB Tier):
- AZ-a: 10.0.21.0/24 (256 IP)
- AZ-c: 10.0.22.0/24 (256 IP)
설계 의도: - /24 서브넷은 소규모 서비스에 충분한 IP 범위를 제공합니다. 향후 확장이 필요하면 /20으로 변경할 수 있지만, 서브넷 CIDR은 생성 후 변경이 불가능하므로 초기 설계가 중요합니다. - 2개 AZ에 걸쳐 배치하여 단일 AZ 장애에 대비합니다. 3개 AZ를 사용하면 가용성은 높아지지만 비용도 비례하여 증가합니다. - 계층별로 서브넷을 분리하여 Security Group과 NACL을 계층 단위로 적용할 수 있습니다.
3.2 Route Table 설계
Public Subnet Route Table:
| Destination | Target | 용도 |
|---|---|---|
| 10.0.0.0/16 | local | VPC 내부 통신 |
| 0.0.0.0/0 | Internet Gateway | 인터넷 인바운드/아웃바운드 |
Private Subnet Route Table (App/DB Tier):
| Destination | Target | 용도 |
|---|---|---|
| 10.0.0.0/16 | local | VPC 내부 통신 |
| 0.0.0.0/0 | NAT Gateway | 아웃바운드 인터넷 (패치, API 호출) |
DB Tier에 NAT Gateway가 필요한가?
DB Tier는 일반적으로 외부 인터넷 접근이 불필요합니다. RDS 관리형 서비스는 AWS가 패치를 처리하므로 NAT Gateway 없이 운영할 수 있습니다. 다만 DB에서 외부 API를 호출해야 하는 경우(예: Lambda 트리거로 외부 알림 전송)에는 NAT Gateway 또는 VPC Endpoint가 필요합니다.
3.3 NAT Gateway 배치 전략
NAT Gateway는 AZ당 1개를 배치하는 것이 고가용성 관점에서 권장됩니다.
| 구성 | 장점 | 단점 |
|---|---|---|
| NAT Gateway 1개 (단일 AZ) | 비용 절감 (~$45/월) | 해당 AZ 장애 시 Private Subnet 전체 인터넷 차단 |
| NAT Gateway 2개 (AZ별) | AZ 장애 격리 | 비용 2배 (~$90/월) |
비용이 제한적인 초기 단계에서는 NAT Gateway 1개로 시작하고, 서비스 안정성 요구가 높아지면 AZ별로 분리하는 것이 현실적인 접근입니다.
4. 보안 설계
4.1 Security Group 설계
3-Tier 아키텍처에서 Security Group은 계층 간 통신만 허용하는 체인 구조로 설계합니다.
ALB Security Group (sg-alb):
| 방향 | 프로토콜 | 포트 | 소스/대상 | 용도 |
|---|---|---|---|---|
| Inbound | TCP | 443 | 0.0.0.0/0 | HTTPS 트래픽 수신 |
| Inbound | TCP | 80 | 0.0.0.0/0 | HTTP → HTTPS 리다이렉트 |
| Outbound | TCP | 8080 | sg-app | App Tier로 전달 |
App Security Group (sg-app):
| 방향 | 프로토콜 | 포트 | 소스/대상 | 용도 |
|---|---|---|---|---|
| Inbound | TCP | 8080 | sg-alb | ALB에서만 트래픽 수신 |
| Outbound | TCP | 5432 | sg-db | DB 접근 |
| Outbound | TCP | 443 | 0.0.0.0/0 | 외부 API 호출 (NAT 경유) |
DB Security Group (sg-db):
| 방향 | 프로토콜 | 포트 | 소스/대상 | 용도 |
|---|---|---|---|---|
| Inbound | TCP | 5432 | sg-app | App Tier에서만 DB 접근 |
| Outbound | — | — | — | 필요 시에만 허용 |
핵심 원칙: Security Group의 소스를 IP 대신 다른 Security Group ID로 지정합니다. 이렇게 하면 App Tier 인스턴스가 Auto Scaling으로 추가/제거되어도 별도의 규칙 변경 없이 통신이 유지됩니다.
4.2 NACL 설계 (선택적 추가 방어)
Security Group만으로도 기본 보안은 충족되지만, 규정 준수(Compliance)나 심층 방어(Defense in Depth)가 필요한 경우 NACL을 추가합니다.
| Subnet | 허용 Inbound | 허용 Outbound | 차단 |
|---|---|---|---|
| Public | 80, 443 (Any) | Ephemeral ports | 불필요한 포트 전체 |
| App Private | 8080 (Public Subnet CIDR) | 5432 (DB Subnet CIDR) | 인터넷 직접 접근 |
| DB Private | 5432 (App Subnet CIDR) | Ephemeral ports | App 외 모든 접근 |
4.3 데이터 암호화
| 구간 | 방법 | 비고 |
|---|---|---|
| 클라이언트 → ALB | TLS 1.2+ (ACM 인증서) | ACM 무료, 자동 갱신 |
| ALB → App | HTTP 또는 TLS | 내부 통신이므로 HTTP 허용 가능, 규정에 따라 TLS 적용 |
| App → DB | TLS (RDS SSL) | rds.force_ssl 파라미터로 강제 |
| DB 저장 데이터 | AES-256 (KMS) | RDS 암호화 활성화 시 자동 적용 |
5. 각 계층별 상세 설계
5.1 Web Tier: ALB 설계
ALB를 선택한 이유:
| 선택지 | 적합한 경우 | 이 시나리오에서의 판단 |
|---|---|---|
| ALB | HTTP/HTTPS 라우팅, 경로 기반 분배 | ✅ 웹 애플리케이션에 적합 |
| NLB | TCP/UDP, 초저지연, 고정 IP 필요 | ❌ L7 기능 불필요 |
| CLB | 레거시 | ❌ 신규 설계에서 사용하지 않음 |
ALB 설정 포인트:
# Target Group 설정
Health Check:
Path: /health
Interval: 30s
Healthy Threshold: 2
Unhealthy Threshold: 3
Timeout: 5s
# Listener Rules
- HTTPS:443 → Default: App Target Group
- HTTP:80 → Redirect to HTTPS:443
# Sticky Session
- 비활성화 (Stateless 설계 권장)
- 세션이 필요하면 ElastiCache(Redis)로 외부화
Sticky Session을 비활성화하는 이유: Sticky Session을 사용하면 특정 인스턴스에 트래픽이 집중될 수 있고, 해당 인스턴스 장애 시 세션이 유실됩니다. 세션을 Redis로 외부화하면 어떤 인스턴스가 요청을 처리해도 동일한 세션 데이터에 접근할 수 있습니다.
5.2 App Tier: Auto Scaling Group 설계
Launch Template 구성:
Instance Type: t3.medium (2 vCPU, 4GB RAM)
AMI: Amazon Linux 2023 (최신 패치 적용)
IAM Role: app-tier-role (S3 읽기, CloudWatch 쓰기, Secrets Manager 읽기)
User Data: 애플리케이션 시작 스크립트
Auto Scaling 정책:
| 정책 | 조건 | 동작 |
|---|---|---|
| Scale Out | CPU 평균 70% 이상 (5분) | 인스턴스 1개 추가 |
| Scale In | CPU 평균 30% 이하 (10분) | 인스턴스 1개 제거 |
| 최소 인스턴스 | — | 2개 (AZ별 1개) |
| 최대 인스턴스 | — | 6개 |
왜 Target Tracking이 아닌 Step Scaling인가?
Target Tracking(목표 추적)은 설정이 간단하지만, 트래픽 패턴이 급격히 변하는 경우 반응이 느릴 수 있습니다. 이 시나리오에서는 B2B SaaS로 트래픽 패턴이 비교적 예측 가능하므로 Target Tracking도 적합합니다. 다만 Scale In 속도를 세밀하게 제어하고 싶다면 Step Scaling이 더 유연합니다.
배포 전략:
# Rolling Update 설정
MinInstancesInService: 1
MaxBatchSize: 1
PauseTime: PT5M
WaitOnResourceSignals: true
이 설정은 인스턴스를 1개씩 교체하면서 최소 1개는 항상 서비스 중인 상태를 유지합니다. 배포 중에도 서비스가 중단되지 않습니다.
5.3 DB Tier: RDS Multi-AZ 설계
RDS 구성:
Engine: PostgreSQL 15
Instance Class: db.t3.medium (2 vCPU, 4GB RAM)
Storage: gp3, 100GB, 3000 IOPS
Multi-AZ: Enabled (Standby in AZ-c)
Backup:
Retention: 7일
Window: 03:00-04:00 UTC (한국 시간 12:00-13:00)
Encryption: AES-256 (AWS KMS)
Multi-AZ 동작 방식: - Primary 인스턴스(AZ-a)와 Standby 인스턴스(AZ-c)가 동기식으로 복제됩니다. - Primary 장애 시 자동으로 Standby가 승격됩니다 (일반적으로 60~120초). - 애플리케이션은 RDS Endpoint(DNS)를 사용하므로 Failover 시 코드 변경이 불필요합니다.
Read Replica를 추가해야 하는 시점: - 읽기 트래픽이 전체의 80% 이상일 때 - 리포트/분석 쿼리가 운영 DB 성능에 영향을 줄 때 - 이 시나리오(5,000 MAU)에서는 아직 불필요합니다. 트래픽이 10배 이상 증가하면 검토합니다.
6. 고가용성과 장애 대응
6.1 장애 시나리오별 대응
| 장애 시나리오 | 영향 범위 | 자동 복구 | 복구 시간 |
|---|---|---|---|
| App 인스턴스 1개 장애 | 없음 (ALB가 제외) | ✅ Health Check → 새 인스턴스 | 2~5분 |
| AZ-a 전체 장애 | 용량 50% 감소 | ✅ AZ-c에서 계속 서비스 | 즉시 |
| RDS Primary 장애 | DB 일시 중단 | ✅ Multi-AZ Failover | 60~120초 |
| ALB 장애 | 서비스 전체 중단 | ✅ AWS 관리형 (자동 복구) | 수 초 |
| NAT Gateway 장애 | App 외부 통신 차단 | ❌ AZ별 NAT 필요 | 수동 전환 필요 |
6.2 모니터링 설계
각 계층에서 감시해야 할 핵심 메트릭:
Web Tier (ALB): - HTTPCode_Target_5XX_Count: App 서버 오류 감지 - TargetResponseTime: 응답 지연 감지 - HealthyHostCount: 정상 인스턴스 수
App Tier (EC2/ASG): - CPUUtilization: Auto Scaling 트리거 - MemoryUtilization: CloudWatch Agent 필요 - StatusCheckFailed: 인스턴스 하드웨어 장애
DB Tier (RDS): - DatabaseConnections: 커넥션 풀 고갈 감지 - FreeStorageSpace: 디스크 부족 사전 경고 - ReadLatency / WriteLatency: 쿼리 성능 저하
7. 비용 분석
7.1 월간 예상 비용 (서울 리전 기준)
| 리소스 | 사양 | 월 예상 비용 |
|---|---|---|
| ALB | 1개 | ~$18 + LCU 비용 |
| EC2 (App) | t3.medium × 2 | ~$76 |
| RDS Multi-AZ | db.t3.medium (PostgreSQL) | ~$105 |
| NAT Gateway | 1개 | ~$33 + 데이터 처리 비용 |
| EBS (gp3) | 20GB × 2 (App) + 100GB (RDS 포함) | ~$15 |
| Data Transfer | 월 100GB 가정 | ~$10 |
| 합계 | ~$260~$350/월 |
비용은 서울 리전(ap-northeast-2) 기준 On-Demand 가격이며, 트래픽 규모와 LCU 사용량에 따라 변동됩니다. 정확한 견적은 AWS Pricing Calculator로 확인할 수 있습니다.
7.2 비용 최적화 옵션
| 방법 | 절감 효과 | 적용 조건 |
|---|---|---|
| Reserved Instance (1년) | EC2 ~40%, RDS ~40% | 12개월 이상 운영 확정 시 |
| Savings Plan | EC2 ~30% | 사용량 예측 가능 시 |
| NAT Gateway → VPC Endpoint | NAT 비용 제거 | AWS 서비스만 접근하는 경우 |
| Graviton 인스턴스 (t4g) | ~20% 절감 | ARM 호환 애플리케이션 |
| 단일 NAT Gateway | ~$45 절감 | 가용성 요구가 낮은 경우 |
비용 vs 가용성 trade-off:
이 시나리오에서 가장 큰 비용 항목은 RDS Multi-AZ입니다. Single-AZ로 변경하면 약 $70/월을 절감할 수 있지만, DB 장애 시 복구에 수십 분이 소요될 수 있습니다. B2B SaaS에서 업무 시간 중 DB 장애는 고객 이탈로 이어질 수 있으므로, Multi-AZ 비용은 보험으로 간주하는 것이 일반적입니다.
8. 확장 시 고려사항
8.1 트래픽 10배 증가 시
서비스가 성장하여 MAU 50,000명 규모가 되면 다음을 검토합니다.
| 영역 | 현재 | 확장 방안 |
|---|---|---|
| App Tier | t3.medium × 2~6 | c6g.large × 4~12 + Graviton 전환 |
| DB | db.t3.medium Single Writer | db.r6g.large + Read Replica 2개 |
| 캐시 | 없음 | ElastiCache Redis (세션 + 쿼리 캐시) |
| CDN | 없음 | CloudFront (정적 자산 오프로드) |
| NAT | 1개 | AZ별 1개 (고가용성) |
8.2 마이크로서비스 전환 시
3-Tier 아키텍처는 모놀리식 애플리케이션에 적합한 구조입니다. 서비스가 더 커지면 다음 단계를 고려할 수 있습니다.
- ECS/EKS 전환: App Tier를 컨테이너 기반으로 변경하여 서비스별 독립 배포
- API Gateway 추가: 서비스 간 라우팅, 인증, Rate Limiting 중앙화
- 서비스별 DB 분리: 각 마이크로서비스가 자체 데이터 저장소를 소유
다만 마이크로서비스 전환은 조직 규모와 개발 속도가 뒷받침되어야 합니다. 5~10명 규모의 팀에서는 3-Tier 모놀리식이 오히려 생산성이 높을 수 있습니다.
9. 설계 체크리스트
네트워크
- [ ] VPC CIDR이 향후 확장을 고려한 크기인가
- [ ] 최소 2개 AZ에 걸쳐 서브넷을 배치했는가
- [ ] DB Subnet은 인터넷 접근이 차단되어 있는가
- [ ] Route Table이 계층별로 분리되어 있는가
보안
- [ ] Security Group이 계층 간 체인 구조로 설계되었는가
- [ ] DB는 App Tier에서만 접근 가능한가
- [ ] HTTPS가 강제되고 있는가 (HTTP → HTTPS 리다이렉트)
- [ ] RDS 암호화가 활성화되어 있는가
- [ ] IAM Role이 최소 권한으로 설정되어 있는가
가용성
- [ ] ALB가 Multi-AZ로 배포되어 있는가
- [ ] Auto Scaling 최소 인스턴스가 2개 이상인가
- [ ] RDS Multi-AZ가 활성화되어 있는가
- [ ] Health Check가 적절히 설정되어 있는가
운영
- [ ] CloudWatch 알람이 핵심 메트릭에 설정되어 있는가
- [ ] 자동 백업이 활성화되어 있는가
- [ ] 배포 파이프라인이 무중단 배포를 지원하는가
- [ ] 로그가 중앙 집중화되어 있는가 (CloudWatch Logs)
10. 정리
3-Tier 아키텍처는 웹 서비스의 가장 기본적이면서도 실무에서 가장 많이 사용되는 설계 패턴입니다.
이 설계가 적합한 경우: - 모놀리식 웹 애플리케이션을 운영하는 경우 - 팀 규모가 5~15명이고, 인프라 복잡도를 낮추고 싶은 경우 - 가용성과 보안 요구가 있지만, 마이크로서비스까지는 불필요한 경우
이 설계가 부적합한 경우: - 서비스별 독립 배포와 확장이 필요한 대규모 시스템 - 이벤트 드리븐 아키텍처가 필요한 경우 - 서버리스 우선 전략을 채택한 경우
핵심은 "계층을 분리하는 것 자체"가 아니라, 각 계층을 독립적으로 확장하고, 장애를 격리하고, 보안 경계를 명확히 하는 것입니다. 이 원칙을 이해하면 3-Tier를 넘어 어떤 아키텍처를 설계하든 동일한 사고 방식을 적용할 수 있습니다.
관련 글
'Cloud > AWS' 카테고리의 다른 글
| AWS S3 기본 개념: 버킷 정책, 버전 관리, 수명 주기 설계 (0) | 2026.06.05 |
|---|---|
| ALB와 NLB 차이: 언제 어떤 Load Balancer를 선택할까 (0) | 2026.06.01 |
| Security Group과 NACL 차이: Stateful vs Stateless, 적용 범위, 운영 전략 (0) | 2026.05.31 |
| Public Subnet과 Private Subnet 차이: Route Table, 보안, 비용 기준으로 정리 (0) | 2026.05.29 |
| NAT Gateway와 VPC Endpoint 차이: 비용, 보안, 트래픽 경로 기준 정리 (0) | 2026.05.29 |