# AWS에서 MariaDB 분리 검토 가이드 > 웹 서버와 DB 서버를 분리할 때의 비용, 성능, 구현 고려사항 분석 > - 작성일: 2026-09-15 / 최종 수정: 2026-09-16 (2장에 CPU 크레딧 원인 추가) > - 현재 환경: AWS EC2 t3a.medium (Apache + PHP + Phaser + MariaDB 함께 운영) > - 문제: 동시접속 150~200명 초과 시 10초 멈춤 > - 이 문서는 **의사결정 가이드**입니다. DB 분리는 선택사항이며, 우선순위는 **안1~5 적용 후**입니다. > > ⚠️ **2026-09-16 갱신:** 초판의 2장은 10초 멈춤의 원인을 "DB와 PHP의 리소스 경쟁" 두 가지로만 > 설명했으나, **인스턴스 CPU 크레딧 소진**이라는 세 번째 원인이 빠져 있었습니다. > 2026-04-14 인스턴스 업그레이드의 실제 사유가 이것입니다. 2-0절에 추가했습니다. > 관련 실측: [260916-load-and-capacity-check/01-web-tier-analysis.md](260916-load-and-capacity-check/01-web-tier-analysis.md) --- ## 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초 멈춤은 왜? 10초 멈춤의 후보 원인은 **세 가지**입니다. 초판은 2-1(리소스 경쟁)만 다뤘습니다. | # | 원인 | 계층 | 현재 상태 (2026-09-16 실측) | |---|---|---|---| | 2-0 | **인스턴스 CPU 크레딧 소진** | 인프라 | ✅ 해소 — 재현 안 됨 | | 2-1 | DB·PHP 리소스 경쟁 | 애플리케이션 | ✅ 대폭 개선 (인덱스 적용) | | 2-2 | Apache 워커 고갈 | 웹 서버 | ✅ 여유 — 피크 busy 204 / 400 (51%) | ### 2-0. 인스턴스 CPU 크레딧 소진 (2026-04-14 장애의 실제 원인) t 계열(`t2`/`t3`/`t3a`)은 **버스터블** 인스턴스입니다. 베이스라인을 넘는 CPU 사용은 적립된 크레딧으로 충당하고, 크레딧이 바닥나면 **Standard 모드에서는 베이스라인까지 강제로 조여집니다.** ``` 동시 접속 증가 → Apache MaxRequestWorkers 가 감당 못 함 → 서버 waiting 과 CPU steal 급등 → CPU 크레딧 소진 → 베이스라인으로 스로틀링 → 약 10초간 무응답 ``` 게스트 OS 안에서는 이 스로틀링이 `vmstat` 의 `st`(steal) 컬럼 급등으로 나타나고, CloudWatch 에서는 `CPUCreditBalance` 가 0에 붙는 것으로 나타납니다. **이것이 2026-04-14 인스턴스 업그레이드를 하게 된 직접적인 사유입니다.** **중요한 점은 이 원인이 DB 분리로 해결되지 않는다는 것입니다.** DB를 RDS로 빼내도 웹 서버 인스턴스의 크레딧 구조는 그대로 남습니다. #### 현재 상태: 재현되지 않음 ✅ 피크 시간대(12:50~15:00) vmstat 779개 샘플 실측입니다. 원본: [260916-load-and-capacity-check/result/peaktime_steal_summary.txt](260916-load-and-capacity-check/result/peaktime_steal_summary.txt) | | 9/14 (인덱스 개선 전) | 9/15 (개선 전) | 9/16 (개선 후) | |---|---|---|---| | steal 평균 | 0.003% | 0.021% | 0.010% | | steal 최대 | 1% | 2% | 1% | | us+sy 평균 | 13.50% | 9.48% | **2.79%** | | 베이스라인(20%) 초과 샘플 | 109개 (14.0%) | 65개 (8.3%) | **1개 (0.1%)** | `t3a.medium` 의 크레딧 베이스라인은 인스턴스 전체 CPU의 **20%** 이고, 이는 `vmstat` 의 `us+sy` 20% 와 같은 값입니다. 인덱스 개선 전에도 피크 평균이 13.5% 로 베이스라인 미만이었으므로 **피크 시간에도 크레딧은 순증하고 있었습니다.** 개선 후에는 2.79% 로 사실상 무관해졌습니다. t2.micro 시절과 비교하면 여유가 십수 배 늘어난 것이 원인입니다. | | t2.micro (2026-04 이전) | t3a.medium (현재) | |---|---|---| | vCPU / 메모리 | 1 / 1GB | 2 / 4GB | | 크레딧 베이스라인 | 10% | 20% | | 시간당 크레딧 (최대 적립) | 6 (144) | 24 (576) | > 미확인: 이 인스턴스의 크레딧 모드가 **Unlimited 인지 Standard 인지** 확인이 필요합니다. > T3 계열 기본값은 Unlimited(스로틀 대신 초과분 과금)지만, t2 에서 마이그레이션한 경우 > Standard 로 넘어왔을 수 있습니다. Standard 라면 위 장애 경로가 이론상 아직 살아 있습니다. > 확인: AWS 콘솔 → EC2 → 인스턴스 → 크레딧 사양, 또는 CloudWatch `CPUSurplusCreditsCharged`. ### 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만 분리해서는 부분적 개선만 가능 #### 2026-09-16 갱신: DB 측은 해소됨 ✅ 9/15 인덱스·쿼리 개선 적용 후 피크 CPU가 크게 떨어졌습니다. | 지표 | 9/15 (개선 전) | 9/16 (개선 후) | 변화 | |---|---|---|---| | 피크 us+sy 평균 | 9.49% | 2.80% | 3.4배 ↓ | | 기록 1,000건당 CPU | 379.8초 | 100.3초 | 3.8배 ↓ | | 디스크 읽기 bi 평균 | 60.5 | 17.4 | 3.5배 ↓ | 출처: [260915-improve-production/result/peaktime_vmstat_summary.txt](260915-improve-production/result/peaktime_vmstat_summary.txt) ### 2-3. Apache 워커 고갈 (웹 계층) prefork MPM 에서는 워커(자식 프로세스)가 **요청 처리 중**만이 아니라 **TCP 연결이 열려 있는 내내** 점유됩니다. `KeepAliveTimeout` 동안 아무 일도 안 하면서 연결만 붙잡습니다. 실측에서 busy 워커의 70~80%가 이 KeepAlive 대기 상태였습니다. 현재 설정과 실부하입니다. | 항목 | 값 | |---|---| | MPM / PHP | prefork / mod_php (PHP-FPM 아님) | | `MaxRequestWorkers` / `ServerLimit` | 400 / 400 | | `KeepAliveTimeout` | 5초 | | HTTP/2 | 미적용 (브라우저가 origin당 연결 최대 6개) | | 평균 요청률 | 3.55 req/s | | 평균 응답 시간 | 15.4 ms | | Apache CPU 점유 | 코어 1개의 **0.42%** | | Apache 메모리 (PSS 합계) | 14프로세스 **29MB** | | `max_connections` / `Max_used_connections` | 151 / **27** | #### 2026-09-17 피크 측정 결과 ✅ 수업 시간(12:50~15:00) 780샘플 실측입니다. | 항목 | 값 | 상한 대비 | |---|---|---| | busy 워커 최대 | **204** | `MaxRequestWorkers` 400의 51% | | 요청률 최대 | 132 req/s | 4일 평균(3.55)의 37배 | | `K`(KeepAlive 대기) | busy 의 **69%** | | | `Max_used_connections` | 27 | `max_connections` 151의 18% | | us+sy 최대 / steal 최대 | 9% / **0%** | 크레딧 베이스라인 초과 0샘플 | **웹 계층도 상한 대비 여유입니다.** 워커 수요는 `busy ≈ 1.74 × req/s` 로, 400 포화점은 약 230 req/s 입니다(실측 피크의 1.74배). `MaxRequestWorkers 400` 은 근거 있는 설정이며 **변경 불필요**합니다. 상세: [260916-load-and-capacity-check/01-web-tier-analysis.md](260916-load-and-capacity-check/01-web-tier-analysis.md) --- ## 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) 필수. #### 2026-09-16 갱신 안1은 9/15 운영 적용을 마쳤고, 효과가 확인됐습니다(2-2절). 그리고 2-0절에서 드러났듯 **10초 멈춤의 원인 중 하나는 애초에 DB 계층이 아니라 인스턴스 CPU 크레딧이었습니다.** 세 원인을 DB 분리가 각각 어떻게 다루는지 정리하면 이렇습니다. | 원인 | DB 분리로 해결되나? | 실제 해결 수단 | |---|---|---| | 2-0 CPU 크레딧 소진 | ❌ 전혀. 웹 인스턴스 구조는 그대로 | 인스턴스 사양 상향 (2026-04-14 완료) | | 2-1 DB·PHP 리소스 경쟁 | ⭕ 부분적 | 인덱스·쿼리 개선 (2026-09-15 완료) | | 2-2 Apache 워커 고갈 | ❌ 전혀. 웹 계층 문제 | MPM·KeepAlive 튜닝 (미측정) | **세 원인 중 DB 분리가 유효한 것은 하나뿐이고, 그 하나는 이미 비용 0원으로 해결됐습니다.** --- ## 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. **안1 적용** (인덱스+쿼리 개선) ```bash # 스테이징 DB에서 테스트 # 1. 현재 쿼리 EXPLAIN 분석 # 2. 인덱스 추가 # 3. 쿼리 조건 개선 # 4. EXPLAIN 재확인 (인덱스 사용 확인) # 5. 성능 측정 (느린 쿼리 로그) ``` - 예상 시간: 2~3시간 - 예상 효과: **10초 멈춤 → 무시할 수 있는 수준** 2. **안5 일부 적용** (N+1 제거) ```bash # 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. 사전 준비 ```bash # 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. 데이터 마이그레이션 ```bash # 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. 애플리케이션 연결 변경 ```php // 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. 테스트 ```bash # 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. 롤백 계획 ```bash # 문제 발생 시 원래 상태로 복원 # 1. 웹 서버 DB 연결 정보 되돌리기 # (localhost 또는 mysql로 변경) # 2. Docker의 MariaDB 컨테이너 재시작 docker restart chocomae-mariadb # 3. 운영 중단 시간: 10~15분 ``` --- ## 9. 체크리스트 ### 완료 (2026-09-15 ~ 09-16) - [x] 안1 (인덱스+쿼리) 문서 읽기: `02-option1-index-and-query-rewrite.md` - [x] 스테이징 DB에서 안1 테스트 (EXPLAIN 전/후) — [260915-improve-stage](260915-improve-stage/) - [x] 성능 향상 확인 후 운영 적용 (9/15 23:00) — [260915-improve-production](260915-improve-production/07-post-analysis.md) - [x] 안5 일부 (N+1, SQL Injection) 문서 읽기: `06-option5-application-layer.md` - [x] 추가 성능 향상 측정 — 피크 CPU 3.4배 감소, 기록 1,000건당 CPU 3.8배 감소 - [x] CPU 크레딧·steal 재검증 — 재현 안 됨 (2-0절) - [x] 웹 계층(Apache) 평상시 부하 측정 — CPU 0.42%, 메모리 29MB (2-3절) - [x] 2026-09-17 피크 모니터링 (워커 버스트 판정) — busy 최대 204/400, 여유 확인 - [x] `MaxRequestWorkers` 판정 — 400 적정, 변경 불필요 ### 지금 바로 할 것 - [ ] 없음 (필수 변경 사항 없음) ### 선택 / 남은 확인 - [ ] 트래픽 증가 전망 시: `KeepAliveTimeout` 5→2, `MaxConnectionsPerChild` 0→10000 - [ ] `MinSpareServers` 현재값 확인 (idle=0 샘플 5.0%) - [ ] EC2 크레딧 모드 확인 (Unlimited / Standard) - [ ] 외부에서 `/server-status` 접근 차단 확인 → 상세: [260916-load-and-capacity-check/01-web-tier-analysis.md](260916-load-and-capacity-check/01-web-tier-analysis.md) ### 그 이후 재평가 - [ ] 10초 멈춤 현상 재발 확인 - [ ] 필요 시: 안2/안3 검토 - [ ] 필요 시: DB 분리 검토 (이때 이 문서 다시 읽기) ### DB 분리 결정 시 - [ ] 현재 DB 전체 백업 (필수) - [ ] RDS 또는 EC2 선택 - [ ] 마이그레이션 계획 (다운타임 계획) - [ ] 스테이징에서 먼저 테스트 - [ ] 모니터링 및 롤백 계획 수립 --- ## 10. 최종 결론 | 질문 | 답변 | 근거 | |---|---|---| | **비용이 절감될까?** | ❌ 아니오. 증가할 가능성. | 대부분의 조합이 월 비용 증가 | | **CPU 부하가 줄까?** | ⚠️ 부분적. | 세 원인 중 하나에만 유효 (4-2절) | | **10초 멈춤이 해결될까?** | ❌ 아니오. | 원인 2-0(크레딧)·2-2(워커)는 웹 계층. DB 분리와 무관 | | **지금 해야 할 일?** | ✅ 없음 | 2026-09-17 측정으로 세 원인 모두 해소 확인 | | **DB 분리 필요한가?** | ❌ 불필요. | 아래 근거 참조 | **2026-09-16 기준 최종 권장: DB 분리하지 마세요.** 초판은 "아마 불필요"였으나, 실측이 쌓이면서 근거가 명확해졌습니다. ``` ① 크레딧 원인 (2-0) → 2026-04-14 인스턴스 상향으로 해소. steal 최대 2%, 재현 안 됨 ② DB 원인 (2-1) → 2026-09-15 인덱스·쿼리 개선으로 해소. 피크 CPU 3.4배 감소 ③ 웹 계층 (2-2) → 2026-09-17 피크 실측. busy 204/400(51%), steal 0%, us+sy 최대 9% → 세 원인이 모두 해소됐고, DB 분리가 유효했던 것은 ② 하나뿐이며 이미 비용 0원으로 해결됨 → 지금 DB를 분리할 이유가 없음 ``` **다음 할 일:** ``` 1. 필수 변경 사항 없음. 현 구성 유지. 2. 트래픽이 1.7배 이상 늘어날 전망이면 (비용 0원, 무중단) → KeepAliveTimeout 5초 → 2초 : 워커 여유 1.74배 → 3.1배 → MaxConnectionsPerChild 0 → 10000 : 누수 누적 방지 상세: 260916-load-and-capacity-check/01-web-tier-analysis.md 6장 3. 위로도 부족해지면 안2/안3 검토 → DB 분리는 그 다음의 마지막 선택지 ``` > 이 문서는 **DB 분리 시점이 오면 다시 읽는 참고 자료**로 보존합니다. > 6~8장의 비용 비교·마이그레이션 절차는 그대로 유효합니다.