1. WhatsTheTime.com - 시간 조회 서비스
비즈니스 요구사항
- 사용자에게 현재 시간을 보여주는 간단한 웹 서비스
- 트래픽이 시간대에 따라 변동
- 고가용성 필요
진화 단계
1단계: 단일 인스턴스 (초기 MVP)
Internet
↓
[Elastic IP]
↓
[EC2 t3.micro]
└─ 애플리케이션 서버
장점:
- 구현이 간단
- 저렴한 비용
문제점:
- 단일 장애점 (SPOF)
- 확장 불가능
- 인스턴스 재시작 시 다운타임
월 예상 비용: ~$10
2단계: Elastic IP + 수직 확장
Internet
↓
[Elastic IP]
↓
[EC2 m5.large] ← 더 큰 인스턴스
개선 사항:
- 더 많은 트래픽 처리 가능
- Elastic IP로 IP 고정
여전한 문제:
- 여전히 SPOF
- 확장 한계 존재
- 다운타임 발생
월 예상 비용: ~$70
3단계: Multi-AZ 고가용성
Internet
↓
[Route 53] - Health Check
↓
┌──────────────┬──────────────┐
│ AZ-A │ AZ-C │
│ [EC2 Primary]│ [EC2 Standby]│
│ [Elastic IP] │ [Elastic IP] │
└──────────────┴──────────────┘
개선 사항:
- 고가용성 확보
- 자동 장애 조치
문제점:
- Standby 서버 유휴 상태 (비용 낭비)
- 수동 확장 필요
월 예상 비용: ~$140
4단계: 로드 밸런서 + Auto Scaling
Internet
↓
[Route 53]
↓
[Application Load Balancer]
↓
[Auto Scaling Group]
├── [EC2] AZ-A
├── [EC2] AZ-A
├── [EC2] AZ-C
└── [EC2] AZ-C
설정:
- Min: 2
- Desired: 4
- Max: 10
- Target: CPU 50%
개선 사항:
- 자동 확장/축소
- 모든 인스턴스 활성 사용
- 비용 최적화
- Elastic IP 불필요
월 예상 비용: $80-200 (트래픽에 따라)
5단계: 예약 인스턴스로 비용 절감
[Auto Scaling Group]
├── [예약 인스턴스 2개] ← 기본 용량 (40% 할인)
└── [온디맨드 0-8개] ← 확장 용량
비용 절감:
- 기본 2개 인스턴스: 1년 예약 (40% 할인)
- 확장 인스턴스: 온디맨드
월 예상 비용: $60-180
최종 아키텍처 (프로덕션 레벨)
Internet
↓
[Route 53] - Health Check
↓
[CloudFront] ← CDN 추가
↓
[Application Load Balancer]
↓ HTTPS (SSL 종료)
[Auto Scaling Group]
├── [EC2] AZ-A
├── [EC2] AZ-A
├── [EC2] AZ-C
└── [EC2] AZ-C
↓ 캐싱
[ElastiCache Redis]
↓
[RDS Multi-AZ]
최종 개선 사항:
- CloudFront로 글로벌 성능 향상
- ElastiCache로 DB 부하 감소
- RDS Multi-AZ로 데이터 고가용성
- SSL/TLS 보안 적용
월 예상 비용: $200-400
2. MyClothes.com - 쇼핑몰 서비스
비즈니스 요구사항
- 상품 목록 조회
- 장바구니 기능
- 사용자 세션 관리
- 글로벌 배송
아키텍처 설계
프론트엔드 계층
사용자
↓
[Route 53]
↓
[CloudFront]
├── Origin: S3 (정적 콘텐츠)
│ └── HTML, CSS, JS, 이미지
└── Origin: ALB (동적 콘텐츠)
└── API 요청
정적 콘텐츠 전략:
- S3에 React/Vue 빌드 파일 배포
- CloudFront로 전 세계 배포
- 버전 관리:
v1.0.1/,v1.0.2/
동적 콘텐츠:
- API Gateway 또는 ALB
- Lambda 또는 EC2
애플리케이션 계층
[Application Load Balancer]
↓
[Auto Scaling Group]
├── [EC2 - Spring Boot]
├── [EC2 - Spring Boot]
└── [EC2 - Spring Boot]
↓
세션 저장소: [ElastiCache Redis]
세션 관리 전략:
❌ 로컬 세션 (문제)
사용자 → ALB → EC2-1 (로그인) ✅
사용자 → ALB → EC2-2 (세션 없음) ❌
✅ ElastiCache 세션 (해결)
EC2-1 ─┐
EC2-2 ─┤→ [Redis] ← 중앙 세션 저장소
EC2-3 ─┘
어느 서버로 가도 세션 유지 ✅
Spring Boot 설정:
// build.gradle
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.session:spring-session-data-redis'
}
// application.yml
spring:
session:
store-type: redis
redis:
host: elasticache-endpoint.cache.amazonaws.com
port: 6379
장바구니 관리
옵션 1: Redis (추천)
// 장바구니 추가
redisTemplate.opsForList().rightPush("cart:user123", productId);
// 장바구니 조회
List<String> cart = redisTemplate.opsForList().range("cart:user123", 0, -1);
// 만료 시간 설정 (24시간)
redisTemplate.expire("cart:user123", 24, TimeUnit.HOURS);
장점:
- 빠른 속도 (메모리 기반)
- TTL 자동 처리
- 구매 전까지는 DB 부하 없음
옵션 2: DynamoDB
# 장바구니 항목 저장
table.put_item(
Item={
'userId': 'user123',
'productId': 'prod456',
'quantity': 2,
'ttl': int(time.time()) + 86400 # 24시간
}
)
장점:
- 서버리스 (관리 불필요)
- 무제한 확장
- TTL 자동 삭제
데이터베이스 계층
[RDS Aurora MySQL]
├── Writer Instance (쓰기)
│ └── 주문, 재고 업데이트
└── Reader Instances (읽기)
└── 상품 조회, 주문 내역
테이블 설계:
-- 상품 테이블
CREATE TABLE products (
product_id VARCHAR(50) PRIMARY KEY,
name VARCHAR(200),
description TEXT,
price DECIMAL(10,2),
stock INT,
image_url VARCHAR(500)
);
-- 주문 테이블
CREATE TABLE orders (
order_id VARCHAR(50) PRIMARY KEY,
user_id VARCHAR(50),
total_amount DECIMAL(10,2),
status VARCHAR(20),
created_at TIMESTAMP
);
-- 주문 상세 테이블
CREATE TABLE order_items (
order_item_id BIGINT PRIMARY KEY AUTO_INCREMENT,
order_id VARCHAR(50),
product_id VARCHAR(50),
quantity INT,
price DECIMAL(10,2)
);
읽기/쓰기 분리:
@Service
public class ProductService {
@Autowired
@Qualifier("writerDataSource")
private JdbcTemplate writerTemplate;
@Autowired
@Qualifier("readerDataSource")
private JdbcTemplate readerTemplate;
// 읽기: Reader 사용
public List<Product> getProducts() {
return readerTemplate.query("SELECT * FROM products", ...);
}
// 쓰기: Writer 사용
public void updateStock(String productId, int quantity) {
writerTemplate.update(
"UPDATE products SET stock = stock - ? WHERE product_id = ?",
quantity, productId
);
}
}
이미지 저장소
[S3 Bucket - Product Images]
├── products/
│ ├── prod001.jpg
│ ├── prod002.jpg
│ └── ...
└── thumbnails/
├── prod001_thumb.jpg
└── prod002_thumb.jpg
[CloudFront] ← CDN
└── https://d1234567.cloudfront.net/products/prod001.jpg
S3 이벤트 트리거로 썸네일 자동 생성:
S3 Upload (원본 이미지)
↓ S3 Event
[Lambda Function]
├── 이미지 리사이징 (Sharp/Pillow)
└── 썸네일 S3 저장
전체 아키텍처
┌─────────────────────────────────────────┐
│ CloudFront (CDN) │
├────────────────┬────────────────────────┤
│ Origin: S3 │ Origin: ALB │
│ (정적 파일) │ (API) │
└────────────────┴────────────────────────┘
↓
┌─────────────────────────┐
│ Application Load Balancer│
└─────────────────────────┘
↓
┌─────────────────────────┐
│ Auto Scaling Group │
│ ├─ EC2 (Spring Boot) │
│ ├─ EC2 (Spring Boot) │
│ └─ EC2 (Spring Boot) │
└─────────────────────────┘
↓ ↓
┌────────┴────┐ ┌────────────┐
│ ElastiCache │ │ RDS Aurora │
│ Redis │ │ MySQL │
│ (세션/캐시) │ │ (주문/상품) │
└─────────────┘ └────────────┘
↓
┌──────────────┐
│ S3 (이미지) │
└──────────────┘
3. MyWordPress.com - 블로그 플랫폼
비즈니스 요구사항
- WordPress 멀티 사이트
- 빠른 이미지 로딩
- 확장 가능한 아키텍처
아키텍처 설계
Internet
↓
[Route 53]
↓
[Application Load Balancer]
↓
[Auto Scaling Group]
├── [EC2 - WordPress] AZ-A
└── [EC2 - WordPress] AZ-C
↓ ↓
[EFS] [Aurora MySQL]
(공유 파일) (데이터베이스)
핵심 포인트
1. EFS로 파일 공유
문제:
사용자 → EC2-1 (업로드 image.jpg) ✅
사용자 → EC2-2 (image.jpg 없음) ❌
해결: EFS 마운트
# 모든 EC2 인스턴스에서 EFS 마운트
sudo mount -t efs fs-12345678:/ /var/www/html/wp-content/uploads
# /etc/fstab에 추가 (자동 마운트)
fs-12345678:/ /var/www/html/wp-content/uploads efs defaults,_netdev 0 0
이제 모든 인스턴스가 동일한 파일 공유:
EC2-1 ─┐
EC2-2 ─┤→ [EFS: /wp-content/uploads]
EC2-3 ─┘
2. Aurora MySQL
wp-config.php 설정:
// Writer Endpoint (쓰기)
define('DB_HOST', 'mywordpress-cluster.cluster-xxxxx.ap-northeast-2.rds.amazonaws.com');
// Reader Endpoint (읽기) - 선택적
define('DB_HOST_READER', 'mywordpress-cluster.cluster-ro-xxxxx.ap-northeast-2.rds.amazonaws.com');
3. CloudFront 추가 (선택)
[CloudFront]
├── Origin: ALB (동적 콘텐츠)
│ └── PHP 페이지
└── Behavior: /wp-content/uploads/*
└── Origin: S3 또는 EFS (이미지)
개선 사항:
- 이미지 로딩 속도 향상
- 글로벌 배포
- ALB 부하 감소
성능 최적화
1. Redis 캐시 추가
[WordPress] → [Redis] → [Aurora]
↑
캐시 플러그인
(W3 Total Cache, Redis Object Cache)
플러그인 설정:
// wp-config.php
define('WP_REDIS_HOST', 'redis-endpoint.cache.amazonaws.com');
define('WP_REDIS_PORT', 6379);
define('WP_CACHE', true);
2. CDN 구성
정적 파일:
- CSS, JS → CloudFront
- 이미지 → CloudFront (EFS Origin)
- 동적 페이지 → ALB
4. 애플리케이션을 빠르게 인스턴스화하기
문제: User Data 스크립트가 느림
#!/bin/bash
yum update -y # 5분
yum install -y httpd # 2분
systemctl start httpd # 30초
# 총 7분 30초 소요
Auto Scaling 시:
- 트래픽 증가 감지: 1분
- 인스턴스 시작: 1분
- User Data 실행: 7분 30초
- 헬스 체크 통과: 1분
- 총 10분 30초 ← 너무 느림!
해결책
방법 1: Golden AMI
개념:
- 애플리케이션이 미리 설치된 AMI 생성
- 부팅 즉시 서비스 시작
생성 과정:
# 1. 기본 인스턴스 생성
# 2. 소프트웨어 설치 및 설정
yum install -y httpd php mysql
# 애플리케이션 배포
# 설정 파일 구성
# 3. AMI 생성
aws ec2 create-image \
--instance-id i-1234567890abcdef0 \
--name "MyApp-Golden-v1.0.0"
효과:
- User Data 실행: 7분 30초 → 30초
- 총 시작 시간: 10분 30초 → 3분
단점:
- AMI 업데이트 필요 (버전 관리)
- 빌드 파이프라인 복잡도 증가
방법 2: User Data + EFS
User Data를 최소화:
#!/bin/bash
# EFS 마운트만 수행
mount -t efs fs-12345678:/ /var/app
# 애플리케이션은 EFS에 미리 배포됨
systemctl start myapp
효과:
- User Data: 30초 이내
- 배포 업데이트: EFS만 수정하면 됨
방법 3: Hybrid (Golden AMI + User Data)
Golden AMI:
- OS 패키지
- 런타임 환경
- 기본 설정
User Data:
- 환경별 설정 (dev/prod)
- 최신 애플리케이션 코드 다운로드
- 동적 설정 적용
#!/bin/bash
# S3에서 최신 코드 다운로드
aws s3 cp s3://my-deployments/app-v1.2.3.jar /opt/app/
# 환경 변수 설정
export DB_HOST=${DB_ENDPOINT}
export REDIS_HOST=${REDIS_ENDPOINT}
# 애플리케이션 시작
systemctl start myapp
효과:
- 빠른 시작: 2-3분
- 유연한 배포
- AMI 재생성 빈도 감소
5. Elastic Beanstalk 개요
개념
Elastic Beanstalk는 AWS의 PaaS(Platform as a Service)로, 인프라를 자동으로 관리
개발자가 하는 것:
- 코드 작성
- ZIP 파일 업로드
Beanstalk가 하는 것:
- EC2 인스턴스 생성
- Auto Scaling 구성
- Load Balancer 설정
- 모니터링 설정
- 배포 자동화
Beanstalk 아키텍처
[Elastic Beanstalk]
├── [Application Load Balancer]
│ └── [Auto Scaling Group]
│ ├── [EC2] - Your App
│ ├── [EC2] - Your App
│ └── [EC2] - Your App
├── [RDS] (선택적)
├── [ElastiCache] (선택적)
└── [CloudWatch] (모니터링)
지원 플랫폼
- Java: Spring Boot, Tomcat
- Node.js: Express, Nest.js
- Python: Django, Flask
- Ruby: Rails, Sinatra
- .NET: ASP.NET Core
- PHP: Laravel, Symfony
- Go: Gin, Echo
- Docker: 커스텀 컨테이너
사용 예시
CLI로 배포
# EB CLI 설치
pip install awsebcli
# 초기화
eb init -p python-3.9 my-app --region ap-northeast-2
# 환경 생성 및 배포
eb create prod-env
# 코드 업데이트
git commit -am "Update feature"
eb deploy
# 환경 상태 확인
eb status
eb health
# 로그 확인
eb logs
# SSH 접속
eb ssh
# 환경 삭제
eb terminate prod-env
배포 전략
1. All at once (전체 동시)
모든 인스턴스 동시 업데이트 → 다운타임 발생 (짧음) → 빠른 배포 → 개발 환경에 적합
2. Rolling (순차)
배치 단위로 순차 업데이트
배치 1: [Old] [Old] → [New] [New]
배치 2: [Old] [Old] → [New] [New]
→ 다운타임 없음
→ 배포 중 용량 감소
3. Rolling with additional batch
추가 인스턴스 생성 후 순차 업데이트
[Old] [Old] [Old] [Old] + [New] [New]
→ [New] [New] [New] [New]
→ 다운타임 없음
→ 전체 용량 유지
→ 추가 비용 발생 (일시적)
4. Immutable (불변)
완전히 새로운 Auto Scaling Group 생성
Old ASG: [Old] [Old] [Old]
New ASG: [New] [New] [New] ← 테스트
→ 성공 시 Old ASG 제거
→ 가장 안전
→ 빠른 롤백
→ 비용 높음 (2배)
5. Blue/Green
새 환경 완전 생성
Blue (구버전): www.example.com
Green (신버전): www-staging.example.com
테스트 완료 후 DNS 스왑:
www.example.com → Green
www-staging.example.com → Blue
→ 즉시 롤백 가능
→ 제로 다운타임
→ 비용 가장 높음
비용 비교
직접 관리 vs Beanstalk
직접 관리 (DIY):
EC2: $70
ALB: $20
운영 시간: 20시간/월 × $50/시간 = $1,000
─────────────
총: $1,090/월
Elastic Beanstalk:
EC2: $70
ALB: $20
Beanstalk: $0 (무료!)
운영 시간: 2시간/월 × $50/시간 = $100
─────────────
총: $190/월 (82% 절감)
- 단순하게 시작하여 점진적으로 개선
- Auto Scaling + ALB로 확장성 확보
- ElastiCache로 세션 및 캐시 관리
- EFS로 파일 공유 (WordPress 등)
- Golden AMI로 빠른 시작
- Elastic Beanstalk로 운영 부담 감소
Share article