현재 서비스중인 t3a.medium 실행 지표 상태 확인

This commit is contained in:
2026-09-18 12:30:12 +09:00
parent 03eea2098e
commit b18612277c
18 changed files with 14858 additions and 68 deletions
+182 -21
View File
@@ -1,10 +1,15 @@
# AWS에서 MariaDB 분리 검토 가이드
> 웹 서버와 DB 서버를 분리할 때의 비용, 성능, 구현 고려사항 분석
> - 작성일: 2026-09-15
> - 작성일: 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)
---
@@ -22,6 +27,63 @@
## 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. 리소스 경쟁 구조
```
@@ -54,6 +116,57 @@
→ 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. 비용 분석: 분리하면 저렴할까?
@@ -119,6 +232,21 @@
**결론:** 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를 먼저 적용하세요
@@ -405,17 +533,34 @@ docker restart chocomae-mariadb
## 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 적정, 변경 불필요
### 지금 바로 할 것
- [ ] 안1 (인덱스+쿼리) 문서 읽기: `02-option1-index-and-query-rewrite.md`
- [ ] 스테이징 DB에서 안1 테스트 (EXPLAIN 전/후)
- [ ] 성능 향상 확인 후 운영 적용
- [ ] 안5 일부 (N+1, SQL Injection) 문서 읽기: `06-option5-application-layer.md`
- [ ] 추가 성능 향상 측정
- [ ] 없음 (필수 변경 사항 없음)
### 1~2주 후 재평가
### 선택 / 남은 확인
- [ ] 트래픽 증가 전망 시: `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)
### 그 이후 재평가
- [ ] 동시접속 150~200명에서 응답시간 측정
- [ ] 10초 멈춤 현상 재발 확인
- [ ] 필요 시: 안2/안3 검토
- [ ] 필요 시: DB 분리 검토 (이때 이 문서 다시 읽기)
@@ -435,22 +580,38 @@ docker restart chocomae-mariadb
| 질문 | 답변 | 근거 |
|---|---|---|
| **비용이 절감될까?** | ❌ 아니오. 증가할 가능성. | 대부분의 조합이 월 비용 증가 |
| **CPU 부하가 줄까?** | ⚠️ 부분적. | DB와 PHP 둘 다 병목 가능성 높음 |
| **10초 멈춤이 해결될까?** | ⚠️ 완전히 아니오. | DB 분리만으로는 불충분, 안1 필수 |
| **지금 해야 할 일?** | ✅ 안1~5 적용! | 비용 0원, 18배 성능 향상 예상 |
| **DB 분리 필요한가?** | ❓ 아마 불필요. | 안1~5로 충분할 가능성 높음. 나중에 재평가. |
| **CPU 부하가 줄까?** | ⚠️ 부분적. | 세 원인 중 하나에만 유효 (4-2절) |
| **10초 멈춤이 해결될까?** | 아니오. | 원인 2-0(크레딧)·2-2(워커)는 웹 계층. DB 분리와 무관 |
| **지금 해야 할 일?** | ✅ 없음 | 2026-09-17 측정으로 세 원인 모두 해소 확인 |
| **DB 분리 필요한가?** | 불필요. | 아래 근거 참조 |
**최종 권장:**
**2026-09-16 기준 최종 권장: DB 분리하지 마세요.**
초판은 "아마 불필요"였으나, 실측이 쌓이면서 근거가 명확해졌습니다.
```
1. 안1 (인덱스+쿼리) 즉시 적용
→ 10초 멈춤 해결 가능성 매우 높음
① 크레딧 원인 (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%
2. 안5 일부 (N+1) 적용
→ 추가 성능 향상
3. 1~2주 후 모니터링
→ 문제 해결됨? → 끝. DB 분리 불필요.
→ 문제 지속? → 안2/안3 검토 → DB 분리는 마지막 선택지
→ 세 원인이 모두 해소됐고, 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장의 비용 비교·마이그레이션 절차는 그대로 유효합니다.