14 KiB
14 KiB
AWS에서 MariaDB 분리 검토 가이드
웹 서버와 DB 서버를 분리할 때의 비용, 성능, 구현 고려사항 분석
- 작성일: 2026-09-15
- 현재 환경: AWS EC2 t3a.medium (Apache + PHP + Phaser + MariaDB 함께 운영)
- 문제: 동시접속 150~200명 초과 시 10초 멈춤
- 이 문서는 의사결정 가이드입니다. DB 분리는 선택사항이며, 우선순위는 안1~5 적용 후입니다.
1. 현재 상황 요약
| 항목 | 현재 상태 |
|---|---|
| 인스턴스 | AWS EC2 t3a.medium (2 vCPU, 4GB RAM) |
| 운영 비용 | $0.094/시간 ≈ 월 $67 |
| 실행 환경 | Docker: Apache + PHP + Phaser (웹) + MariaDB (DB) 동시 운영 |
| 병목 현상 | 동시접속 150~200명 초과 → 10초 멈춤 (CPU/메모리 부족) |
| 단일 실패점 | 인스턴스 1개 → 장애 시 모든 서비스 다운 |
2. 원인 분석: 10초 멈춤은 왜?
2-1. 리소스 경쟁 구조
┌─────────────────────────────────────┐
│ t3a.medium (2 vCPU, 4GB) │
│ ├─ Apache (PHP) │
│ │ ├─ 요청 처리 │
│ │ └─ DB 쿼리 (네트워크 기다림) │
│ │ │
│ └─ MariaDB │
│ ├─ 쿼리 실행 │
│ └─ 인덱스 스캔 (CPU/메모리 사용)│
│ │
│ 리소스: CPU ◐◐ 메모리 ◐◐ │
└─────────────────────────────────────┘
동시접속 150~200명:
- 각 요청이 DB 쿼리 실행 → MariaDB가 리소스 사용량 증가
- PHP도 동시에 요청 처리 → 둘이 2 vCPU를 놓고 경쟁
- 결과: 한쪽이 기다리는 동안 다른 쪽이 처리 → 10초 멈춤
2-2. 실제 병목이 어디인가?
지난 분석 (01-07 문서)에서 발견:
- DB 문제 多: 인덱스 부족, 함수로 감싼 조건(
DATE(),HOUR()등), N+1 쿼리 - PHP도 함께: 동시 요청 처리에 CPU 필요
결론: DB와 PHP 둘 다 병목일 가능성 높음
→ DB만 분리해서는 부분적 개선만 가능
3. 비용 분석: 분리하면 저렴할까?
3-1. 시나리오별 월 비용 비교
| 시나리오 | 웹 서버 | DB 서버 | 월 비용 | 변화 | 평가 |
|---|---|---|---|---|---|
| 현재 (분리 안 함) | t3a.medium | (없음) | $67 | — | — |
| 시나리오 A | t3a.small | RDS micro | $48 | ↓10% | 절감 (웹 성능↓ 위험) |
| 시나리오 B | t3a.small | RDS small | $58 | ↓13% | 절감 (안정성↑) |
| 시나리오 C | t3a.medium | RDS micro | $79 | ↑18% | 증가 (안정성↑) |
| 시나리오 D | t3a.medium | RDS small | $92 | ↑37% | 증가 (고가용성) |
추가 비용 (모든 시나리오):
- RDS 자동 백업: +$1~3/월
- 멀티 AZ (선택): +$50~80/월
- EC2 ↔ RDS 데이터 전송: 무료 (같은 VPC 내)
3-2. 비용 절감 결론
❌ 대부분 비용 증가 또는 현상 유지
- t3a.small으로 다운사이징 시 10% 절감 가능 but 웹 성능 저하 위험
- 안정성을 위해 t3a.medium 유지 필요 → 비용 18~37% 증가
- 결론: 비용 절감 기대 어려움
4. 성능 분석: 10초 멈춤이 해결될까?
4-1. DB 분리의 성능 효과
시나리오 A: DB가 유일한 병목이었다면
분리 전:
동시접속 (150~200) → PHP 대기 → DB 느림 → 멈춤 10초
분리 후:
동시접속 (150~200) → PHP (빠름) + DB 서버 (독립) → 개선
예상: 5~7초 감소 ⭐⭐⭐ (큰 효과)
시나리오 B: PHP도 병목이었다면 (가능성 높음)
분리 전:
동시접속 (150~200) → PHP 과부하 + DB 과부하 → 멈춤 10초
분리 후:
동시접속 (150~200) → PHP 여전히 과부하 + DB 서버 (독립) → 부분 개선
예상: 2~3초 감소만 ⭐ (효과 제한적)
4-2. 실제로 DB만 분리하면 충분한가?
지난 분석(01-07)에서 발견된 쿼리 문제:
- 인덱스 없이 120만 행 전체 스캔 (0.93초)
DATE(),HOUR()함수로 인덱스 무효화- N+1 쿼리: 앱 10개 = DB 쿼리 10번
- 동시접속 150명 × 이런 쿼리 = CPU 폭증
결론: DB 분리만으로는 완전 해결 불가. 인덱스+쿼리 최적화(안1) 필수.
5. 권장 순서: 안1~5를 먼저 적용하세요
5-1. 왜 DB 분리 전에 안1~5를 해야 하나?
| 단계 | 작업 | 비용 | 구현 시간 | 성능 효과 | 필수도 |
|---|---|---|---|---|---|
| 1단계 | 안1: 인덱스+쿼리 | $0 | 2~3시간 | 18배 향상 | ⭐⭐⭐ |
| 2단계 | 안5 일부: N+1, SQL Injection | $0 | 3~4시간 | 2~3배 향상 | ⭐⭐⭐ |
| 3단계 | 안2/안3: 집계, 아카이빙 | $0 | 1~2주 | 지속적 개선 | ⭐⭐ |
| 미래 | DB 분리 (선택사항) | $600~1000/연간 | 2~3일 | 부분 개선 | ⭐ |
안1 적용의 예상 효과:
현재 (느린 쿼리):
┌─ 동시접속 150명
│ └─ 각각 0.93초 쿼리 × 5~10번
│ = 평균 5~10초 지연
└─ 인스턴스 꽉 찼음 → 10초 멈춤
안1 적용 후:
┌─ 동시접속 150명
│ └─ 각각 0.05초 쿼리 × 5~10번
│ = 평균 0.25~0.5초 지연
└─ 여유 있음 → 멈춤 사라짐
5-2. 체계적 진행 계획
1주차: 안1 (인덱스+쿼리) 스테이징 테스트
→ 효과 확인 (EXPLAIN 전/후, 성능 측정)
→ 운영 적용
1~2주: 안5 일부 (N+1, SQL Injection) 적용
→ 추가 개선
3주 이상: 안2/안3 검토
→ 안1~2로도 충분하면 멈춤
필요하면: DB 분리 재검토
(아마 불필요할 가능성 높음)
6. DB 분리 옵션 분석
6-1. 옵션 A: AWS RDS (관리형, 권장)
구성:
- 웹 서버: t3a.small ($0.047/시간)
- DB 서버: RDS db.t3.micro ($0.017/시간) 또는 db.t3.small ($0.034/시간)
장점:
✅ 자동 백업 (7일, 비용 포함)
✅ 자동 패치 (보안 업데이트 자동 적용)
✅ 멀티 AZ 옵션 (장애 자동 복구)
✅ CloudWatch 모니터링 (무료)
✅ 성능 인사이트 (데이터베이스 부하 가시화)
단점:
❌ 비용 증가 (월 $48~92)
❌ 커스터마이징 제한 (파라미터 일부 수정 불가)
❌ DB 직접 접근 제한 (일부 admin 작업 불가)
❌ 마이그레이션 다운타임 (1~2시간)
RDS 선택 기준:
| 선택 | 상황 | 비용 | 성능 |
|---|---|---|---|
| db.t3.micro | 안1~2 적용 후 여유 충분 | $0.017/시간 | 충분 |
| db.t3.small | 안정성 우선 | $0.034/시간 | 넉넉함 |
6-2. 옵션 B: 별도 EC2 인스턴스
구성:
- 웹 서버: t3a.small ($0.047/시간)
- DB 서버: EC2 t3a.small ($0.047/시간)
장점:
✅ 비용 낮음 (월 $67, 현재와 유사)
✅ 완전한 제어 (모든 설정 수정 가능)
✅ Synology 복제본과 동일 구조 (운영 경험 재사용)
단점:
❌ 직접 백업/관리 필요
❌ 자동 장애 복구 없음 (인스턴스 다운 → 수동 재시작)
❌ 보안 그룹 + 네트워크 설정 복잡
❌ 모니터링 스크립트 직접 작성/관리
6-3. 옵션 C: 분리하지 않음 (권장)
상황:
- 안1 (인덱스+쿼리)로 10초 멈춤 해결됨
- 안5 (N+1)로 동시접속 처리량 2~3배 향상
- 결과: 150~200명 동시접속도 무리 없음
장점:
✅ 추가 비용 0원
✅ 구현 복잡도 낮음 (현재 구조 유지)
✅ 운영 단순함 (Docker 1개 관리)
단점:
❌ 단일 실패점 (인스턴스 다운 = 전체 서비스 다운)
→ 해결책: 08번 문서의 Synology 복제본 운영
7. 의사결정 프레임워크
7-1. 지금 바로 해야 할 것
✅ 즉시 (필수):
-
안1 적용 (인덱스+쿼리 개선)
# 스테이징 DB에서 테스트 # 1. 현재 쿼리 EXPLAIN 분석 # 2. 인덱스 추가 # 3. 쿼리 조건 개선 # 4. EXPLAIN 재확인 (인덱스 사용 확인) # 5. 성능 측정 (느린 쿼리 로그)- 예상 시간: 2~3시간
- 예상 효과: 10초 멈춤 → 무시할 수 있는 수준
-
안5 일부 적용 (N+1 제거)
# SQL Injection 보안 수정 (3개 엔드포인트) # N+1 쿼리 제거 (앱 목록 조회)- 예상 시간: 3~4시간
- 예상 효과: 추가 2~3배 성능 향상
7-2. 안1~2 적용 후 재평가
체크리스트:
☐ 안1 운영 적용 완료
☐ 1주일 모니터링 (slow query log, CPU 사용률)
→ 동시접속 150~200명 시 응답시간 확인
→ 10초 멈춤 재발 확인
결과:
☐ YES: 문제 해결됨 → DB 분리 불필요, Synology 복제만 운영
☐ NO: 문제 지속 → 안5 추가 적용
☐ 안5까지 적용 완료
☐ 2주 모니터링
결과:
☐ YES: 문제 해결됨 → DB 분리 불필요
☐ NO: 여전히 느림 → 다음 중 선택:
(1) 안2/안3 적용 (구조 개선, 1~2주)
(2) DB 분리 검토 (RDS, 2~3일)
7-3. DB 분리 결정 체크리스트
분리가 필요하면:
☐ 안1~5 모두 적용했으나 여전히 느림
☐ AWS 비용 증가를 감수할 수 있음
☐ 마이그레이션 다운타임 (1~2시간) 감수 가능
선택: RDS vs EC2
☐ 관리의 편의성 우선 → RDS 선택
☐ 비용 최소화 우선 → EC2 선택
8. DB 분리 구현 절차 (참고용)
8-1. 사전 준비
# 1. 현재 DB 전체 백업 (필수!)
mariadb-dump -h chocomae.jinaju.com -u backup -p \
--single-transaction \
chocomae > /backup/chocomae_before_separation_$(date +%Y%m%d).sql
# 2. 백업 파일 크기 확인 (보통 수백 MB)
ls -lh /backup/chocomae_before_separation_*.sql
# 3. 백업 정합성 확인
mariadb < /backup/chocomae_before_separation_*.sql chocomae -e "SELECT COUNT(*) FROM best_record;"
8-2. RDS 생성 (AWS Console)
1. RDS 대시보드 → "데이터베이스 생성"
2. 엔진: MariaDB 10.11
3. 인스턴스 클래스: db.t3.micro (비용) 또는 db.t3.small (안정)
4. 스토리지: 20GB (현재 데이터 + 여유)
5. 보안 그룹: 웹 서버 EC2 인스턴스만 접근 허용 (포트 3306)
6. 마스터 사용자 이름: admin
7. 마스터 암호: 강력한 비밀번호 (생성 후 AWS Secrets Manager 저장)
8. 백업: 7일 (기본값)
9. 멀티 AZ: 아니오 (비용 증가, 필요시 나중에)
8-3. 데이터 마이그레이션
# 1. RDS 엔드포인트 확인 (예: chocomae-db.c12345.us-east-1.rds.amazonaws.com)
RDS_ENDPOINT="chocomae-db.c12345.us-east-1.rds.amazonaws.com"
# 2. RDS에서 mariadb 데이터베이스 생성
mariadb -h $RDS_ENDPOINT -u admin -p -e "CREATE DATABASE chocomae CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;"
# 3. 스키마 복원 (구조만)
mariadb -h $RDS_ENDPOINT -u admin -p chocomae < src/web/sql/make_db.sql
mariadb -h $RDS_ENDPOINT -u admin -p chocomae < src/web/sql/insert_app.sql
# 4. 데이터 복원 (백업 파일에서)
mariadb -h $RDS_ENDPOINT -u admin -p chocomae < /backup/chocomae_before_separation_*.sql
# 5. 데이터 정합성 확인
mariadb -h $RDS_ENDPOINT -u admin -p chocomae -e "SELECT COUNT(*) FROM best_record;"
# 기존과 동일해야 함
8-4. 애플리케이션 연결 변경
// src/web/server/setup/NA_service_db_setting.php 수정
// 변경 전:
// $hostName = "localhost"; // 또는 "mysql" (Docker)
// 변경 후:
// $hostName = "chocomae-db.c12345.us-east-1.rds.amazonaws.com";
// $userName = "admin";
// $userPassword = "RDS에서_생성한_암호";
8-5. 테스트
# 1. 스테이징 환경에서 먼저 테스트 (RDS + 로컬 웹 서버)
php src/web/server/player/get_login_key.php # 기본 쿼리 테스트
# 2. 성능 테스트
ab -n 1000 -c 50 https://staging.chocomae.com/ # 50 동시접속
# 3. 운영 서버 웹 서버 설정 변경 (배포 훅 수정)
# → EC2의 Docker 컨테이너가 RDS를 가리키도록
# 4. 운영 환경 테스트 (트래픽 낮은 시간)
8-6. 롤백 계획
# 문제 발생 시 원래 상태로 복원
# 1. 웹 서버 DB 연결 정보 되돌리기
# (localhost 또는 mysql로 변경)
# 2. Docker의 MariaDB 컨테이너 재시작
docker restart chocomae-mariadb
# 3. 운영 중단 시간: 10~15분
9. 체크리스트
지금 바로 할 것
- 안1 (인덱스+쿼리) 문서 읽기:
02-option1-index-and-query-rewrite.md - 스테이징 DB에서 안1 테스트 (EXPLAIN 전/후)
- 성능 향상 확인 후 운영 적용
- 안5 일부 (N+1, SQL Injection) 문서 읽기:
06-option5-application-layer.md - 추가 성능 향상 측정
1~2주 후 재평가
- 동시접속 150~200명에서 응답시간 측정
- 10초 멈춤 현상 재발 확인
- 필요 시: 안2/안3 검토
- 필요 시: DB 분리 검토 (이때 이 문서 다시 읽기)
DB 분리 결정 시
- 현재 DB 전체 백업 (필수)
- RDS 또는 EC2 선택
- 마이그레이션 계획 (다운타임 계획)
- 스테이징에서 먼저 테스트
- 모니터링 및 롤백 계획 수립
10. 최종 결론
| 질문 | 답변 | 근거 |
|---|---|---|
| 비용이 절감될까? | ❌ 아니오. 증가할 가능성. | 대부분의 조합이 월 비용 증가 |
| CPU 부하가 줄까? | ⚠️ 부분적. | DB와 PHP 둘 다 병목 가능성 높음 |
| 10초 멈춤이 해결될까? | ⚠️ 완전히 아니오. | DB 분리만으로는 불충분, 안1 필수 |
| 지금 해야 할 일? | ✅ 안1~5 적용! | 비용 0원, 18배 성능 향상 예상 |
| DB 분리 필요한가? | ❓ 아마 불필요. | 안1~5로 충분할 가능성 높음. 나중에 재평가. |
최종 권장:
1. 안1 (인덱스+쿼리) 즉시 적용
→ 10초 멈춤 해결 가능성 매우 높음
2. 안5 일부 (N+1) 적용
→ 추가 성능 향상
3. 1~2주 후 모니터링
→ 문제 해결됨? → 끝. DB 분리 불필요.
→ 문제 지속? → 안2/안3 검토 → DB 분리는 마지막 선택지