현재 서비스중인 t3a.medium 실행 지표 상태 확인
This commit is contained in:
@@ -0,0 +1,381 @@
|
||||
# 웹 계층(Apache) 부하·용량 분석
|
||||
|
||||
> 2026-04-14 AWS 인스턴스 업그레이드의 배경을 현재 사양에서 재검증하고,
|
||||
> Apache 워커·KeepAlive·DB 연결이 실제로 병목인지 실측으로 판정합니다.
|
||||
> - 작성일: 2026-09-16
|
||||
> - 대상: AWS EC2 `t3a.medium` (2 vCPU, 4GB) — Apache 2.4.58 + mod_php7 + MariaDB
|
||||
> - 선행 작업: [260915-improve-production](../260915-improve-production/07-post-analysis.md) (인덱스·쿼리 개선, 9/15 23:00 적용)
|
||||
> - 관련 문서: [00-check-methods.md](00-check-methods.md) (측정 방법), [09-aws-db-separation.md](../09-aws-db-separation.md) (DB 분리 검토)
|
||||
|
||||
---
|
||||
|
||||
## 1. 배경: 2026-04-14 업그레이드는 왜 했나
|
||||
|
||||
당시 파악된 장애 경로입니다.
|
||||
|
||||
```
|
||||
동시 접속 증가
|
||||
→ Apache MaxRequestWorkers 가 감당 못 함
|
||||
→ 서버 waiting 과 CPU steal 급등
|
||||
→ t2.micro 의 CPU 크레딧 소진
|
||||
→ 약 10초간 무응답
|
||||
```
|
||||
|
||||
당시 분석이 내린 결론은 **`t3.micro` + `MaxRequestWorkers 50`** 이었습니다. 근거는 "서비스 사이클 34초 중 서버 점유 1초(약 3%)" 라는 점유율 모델이었고, 이를 근거로 평상시 동시 사용자 약 800명까지 안정적이라고 추정했습니다.
|
||||
|
||||
**실제로는 그보다 큰 `t3a.medium` 으로 갔습니다.** 즉 문서의 권고안과 실제 구성이 다르므로, 그 문서의 수치는 현재 상태를 설명하지 못합니다.
|
||||
|
||||
| | t2.micro (당시) | t3a.medium (현재) |
|
||||
|---|---|---|
|
||||
| vCPU / 메모리 | 1 / 1GB | 2 / 4GB |
|
||||
| 크레딧 베이스라인 | 10% | 20% |
|
||||
| 시간당 크레딧 | 6 (최대 144) | 24 (최대 576) |
|
||||
|
||||
### 1-1. 당시 계산 모델의 한계
|
||||
|
||||
기록해둡니다. 같은 모델을 다시 쓰지 않기 위해서입니다.
|
||||
|
||||
- **"1 페이지 로드 = 1 요청"이 아닙니다.** `index.html` 하나에 script/link 11개 + jQuery `.load()` 로 header/section/footer 3개를 더 받고, 그 뒤에 PHP 엔드포인트가 붙습니다 ([src/web/main/index.html:36](../../../../src/web/main/index.html#L36)).
|
||||
- **0.5초는 CPU 시간이 아니라 응답 시간**입니다. 3% 를 "CPU 여유"로 읽으면 안 되고 "워커 점유율"로만 읽어야 합니다.
|
||||
- **평균 모델은 버스트를 설명하지 못합니다.** 문제는 평균이 아니라 수업 시작 시각에 몰리는 순간입니다.
|
||||
- **"평상시 500명 → 800명"은 측정값이 아니라** 위 모델에서 나온 추정치입니다.
|
||||
|
||||
---
|
||||
|
||||
## 2. 측정 결과
|
||||
|
||||
### 2-1. CPU 크레딧 / steal — 문제 없음 ✅
|
||||
|
||||
피크 시간대(12:50~15:00) vmstat 로그 779개 샘플에서 `st`(steal) 컬럼을 직접 집계했습니다.
|
||||
원본: [result/peaktime_steal_summary.txt](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%)** |
|
||||
| swpd / si / so | 0 / 0 / 0 | 0 / 0 / 0 | 0 / 0 / 0 |
|
||||
|
||||
`t3a.medium` 의 크레딧 베이스라인은 **인스턴스 전체 CPU의 20%** 이고, 이는 vmstat 의 `us+sy` 20% 와 같은 값입니다. 개선 전에도 피크 평균이 13.5% 로 베이스라인 미만이었으므로 **피크 시간에도 크레딧은 순증하고 있었습니다.**
|
||||
|
||||
→ **4월 장애의 직접 원인(크레딧 소진 → 스로틀링)은 현재 사양에서 재현되지 않습니다.**
|
||||
|
||||
> ⚠️ 스왑이 없습니다(`swpd`/`si`/`so` 모두 0). 메모리 한계에 닿으면 느려지는 게 아니라 OOM Killer 가 동작하고, RSS 가 가장 큰 `mysqld` 가 1순위 표적입니다. 메모리 여유는 별도 감시 대상입니다.
|
||||
|
||||
### 2-2. Apache 설정 현황
|
||||
|
||||
```bash
|
||||
apache2ctl -V | grep -i "Server MPM"
|
||||
ls /etc/apache2/mods-enabled/ | grep mpm
|
||||
grep -RiE "^[[:space:]]*(MaxRequestWorkers|MaxClients|ServerLimit|StartServers|MaxConnectionsPerChild)" /etc/apache2/
|
||||
grep -rihE '^\s*(KeepAlive|MaxKeepAliveRequests|KeepAliveTimeout)' /etc/apache2/apache2.conf /etc/apache2/conf-enabled/ /etc/apache2/sites-enabled/
|
||||
apache2ctl -M | grep -iE 'php|proxy_fcgi|http2|status'
|
||||
```
|
||||
|
||||
| 항목 | 값 | 비고 |
|
||||
|---|---|---|
|
||||
| Apache | 2.4.58 (Ubuntu) | 호스트 설치. 도커 아님 |
|
||||
| MPM | **prefork** | mod_php 때문에 고정 |
|
||||
| `StartServers` | 5 | |
|
||||
| `ServerLimit` | **400** | Debian 기본 150에서 상향돼 있음 |
|
||||
| `MaxRequestWorkers` | **400** | 〃 |
|
||||
| `MaxConnectionsPerChild` | 0 | 자식 프로세스 무한 재사용 |
|
||||
| `KeepAlive` | On | |
|
||||
| `KeepAliveTimeout` | **5** | 워커 점유의 주 원인 (2-5 참조) |
|
||||
| `MaxKeepAliveRequests` | 100 | |
|
||||
| PHP | `php7_module` (mod_php) | PHP-FPM 없음 |
|
||||
| HTTP/2 | **미적용** | `mod_http2` 없음 → 브라우저가 origin당 연결 최대 6개 |
|
||||
| `mod_status` | 있음 | `Require local` (`/etc/apache2/mods-enabled/status.conf`) |
|
||||
|
||||
`mods-available/mpm_event.conf`·`mpm_worker.conf` 의 150은 **비활성 MPM** 이므로 무관합니다.
|
||||
|
||||
### 2-3. Apache 실부하 — 병목 아님 ✅
|
||||
|
||||
`curl -s http://localhost/server-status?auto` 누적값 (`RestartTime` 9/12 06:44 이후 394,325초 = 4일 13시간)
|
||||
|
||||
| 지표 | 계산 | 값 |
|
||||
|---|---|---|
|
||||
| 총 요청 | `Total Accesses` 1,398,433 | **3.55 req/s** |
|
||||
| 평균 응답 시간 | `Total Duration` 21,596,481ms ÷ 요청 수 | **15.4 ms** |
|
||||
| 요청당 CPU | (`CPUChildrenUser` 822.34 + `CPUChildrenSystem` 835.02)초 ÷ 요청 수 | **1.19 ms** |
|
||||
| Apache 총 CPU 점유 | 1,657초 ÷ 394,325초 | **코어 1개의 0.42%** |
|
||||
| 응답 1건 평균 크기 | 4,093,249KB ÷ 요청 수 | 2.9 KB |
|
||||
|
||||
메모리 (`/proc/*/smaps_rollup` 의 PSS 합계, 유휴 시각 기준):
|
||||
|
||||
```
|
||||
apache2 14개 / PSS 합계 29MB / 1개당 평균 2MB
|
||||
```
|
||||
|
||||
> PSS 합계는 공유 페이지를 중복 없이 한 번만 계산하므로 Apache 전체의 실제 메모리 비용입니다.
|
||||
> 단, 이 값은 **유휴 자식** 기준입니다. PHP 요청을 처리한 자식은 더 커지므로 피크 재측정이 필요합니다.
|
||||
|
||||
### 2-4. DB 연결 — 제약 아님 ✅
|
||||
|
||||
| 지표 | 값 |
|
||||
|---|---|
|
||||
| `max_connections` | 151 |
|
||||
| `Max_used_connections` (MariaDB 시작 이래 고수위) | **27** |
|
||||
| 요청 대비 신규 DB 연결 비율 | 요청 130건당 36건 = **28%** |
|
||||
|
||||
요청의 28%만 DB를 타고(나머지는 정적 파일), 연결 하나가 수 ms만 삽니다. 동시 DB 연결은 0.04개 수준으로, 151에 닿으려면 초당 만 단위 신규 연결이 필요합니다.
|
||||
|
||||
→ **`MaxRequestWorkers 400` 이 `max_connections 151` 을 넘는 것은 실무상 문제가 되지 않습니다.**
|
||||
|
||||
### 2-5. KeepAlive 점유 구조 — 확정 ✅ (2026-09-17 측정)
|
||||
|
||||
scoreboard 분해 샘플 (`curl -s http://localhost/server-status?auto` 의 `Scoreboard:` 행)
|
||||
|
||||
| 시각 | busy | idle | K(KeepAlive 대기) | W(전송) | R(수신) | 구간 요청률 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 20:16 | 2 | 8 | 1 | 1 | 0 | — |
|
||||
| 20:30:25 | 15 | 3 | 11 | 1 | 3 | — |
|
||||
| 20:30:30 | 15 | 5 | 6 | 1 | 2 | 2.2 req/s |
|
||||
| 20:30:40 | 7 | 7 | 5 | 1 | 0 | 2.2 req/s |
|
||||
| 20:33:12 | 9 | 6 | 8 | 1 | 0 | — |
|
||||
| 20:33:20 | 5 | 9 | 3 | 1 | 0 | 1.5 req/s |
|
||||
| 20:33:30 | 14 | **0** | 11 | 1 | 2 | 13 req/s |
|
||||
|
||||
**busy 워커의 70~80%가 `K`(KeepAlive 대기)** 입니다. 실제 작업 중인 `W` 는 일관되게 1개입니다.
|
||||
|
||||
prefork 에서는 워커가 **요청 처리 중**만이 아니라 **TCP 연결이 열려 있는 내내** 점유됩니다. 응답을 다 보낸 뒤에도 `KeepAliveTimeout`(5초) 동안 자식 프로세스가 연결을 붙잡습니다. 워커 점유 효율은 15ms / 5,000ms = **0.3%** 입니다.
|
||||
|
||||
**2026-09-17 피크 780샘플로 관계가 확정됐습니다.** 5장 참조 — `K` 는 요청률에 선형 비례합니다.
|
||||
(위 저녁 샘플만 보고 "비례하지 않는다"고 판단했던 것은 표본 부족에 따른 오판이었습니다.)
|
||||
|
||||
---
|
||||
|
||||
## 3. 결론
|
||||
|
||||
### 3-1. 확정된 것
|
||||
|
||||
| 항목 | 결론 |
|
||||
|---|---|
|
||||
| CPU 크레딧 / steal | 문제 없음. steal 최대 2%, 피크에도 베이스라인 미달 |
|
||||
| Apache CPU | 코어의 0.42% |
|
||||
| Apache 메모리 | 14프로세스 29MB (유휴 기준) |
|
||||
| 평상시 워커 | 400 중 2~15개 사용 |
|
||||
| DB 연결 상한 151 | 제약 아님. 고수위 27 |
|
||||
| `MaxRequestWorkers 400` | **유지.** 9/17 피크 busy 204(51%)로 적정 (5장) |
|
||||
|
||||
**현재 지표는 전부 여유입니다. 지금 설정을 바꿀 이유가 없습니다.**
|
||||
|
||||
### 3-2. 분석 중 폐기한 가설
|
||||
|
||||
같은 오류를 반복하지 않기 위해 기록합니다.
|
||||
|
||||
| 가설 | 왜 틀렸나 |
|
||||
|---|---|
|
||||
| mod_php 자식 1개당 10~30MB → 400개면 OOM | 실측 PSS 2MB (유휴). 400개여도 800MB 수준 |
|
||||
| 워커 1개 = DB 연결 1개 → 400 > 151 은 결함 | 요청의 28%만 DB 사용. `K` 상태 워커는 DB 연결을 안 씀. 고수위 27 |
|
||||
| Little's law 로 동시 요청 0.055개 → 120이면 13배 여유 | `Total Duration` 은 **처리 시간**만 포함. KeepAlive 점유가 빠져 실측(busy 2~15)과 100배 차이 |
|
||||
| `K ≈ 요청률 × KeepAliveTimeout` 선형 외삽 | 2.2 req/s 와 13 req/s 모두 `K=11`. 버스트에서 연결 재사용이 작동 |
|
||||
| `MaxRequestWorkers 120` 권장 | **9/17 피크 busy 최대 204.** 120으로 조였다면 수업 시간에 요청이 큐에 쌓였음 (5-3절) |
|
||||
| `K` 는 요청률에 비례하지 않는다 (저녁 샘플 7개 기준) | 780샘플 회귀에서 `K = 1.28 × req/s`, 상관 0.862. 표본 부족에 따른 오판 |
|
||||
| 외부에서 `/server-status` 403 확인 | 도메인 오류로 무효. SSL 인증서는 `www_chocomae_com` ([ssl/README:7](../../../../ssl/README#L7)), `chocomae.jinaju.com` 은 http 전용 |
|
||||
|
||||
### 3-3. DB 분리 검토([09번 문서](../09-aws-db-separation.md))에 주는 시사점
|
||||
|
||||
4월 장애가 Apache 워커 + 인스턴스 크레딧에서 비롯됐다면, DB를 RDS로 분리해도 웹 계층 문제는 그대로 남습니다. 반면 9/16 실측은 DB 개선만으로 피크 CPU가 3.4배 줄었음을 보여줍니다.
|
||||
|
||||
→ **09번 문서의 "DB 분리 불필요" 결론을 강화합니다.**
|
||||
|
||||
다만 09번 문서 2장의 원인 진단이 "DB와 PHP의 리소스 경쟁"으로만 서술돼 있고 **인스턴스 크레딧이라는 세 번째 원인이 빠져 있습니다.** 4월 이력을 반영한 보완이 필요합니다.
|
||||
|
||||
---
|
||||
|
||||
## 4. 남은 측정
|
||||
|
||||
### 4-1. 피크 모니터링 (등록 완료)
|
||||
|
||||
`/home/ubuntu/temp/apache-peak.sh` — 평일 12:50부터 10초 간격 780회(130분). 기존 vmstat 모니터링과 같은 시각에 돌아 로그를 나란히 대조할 수 있습니다.
|
||||
|
||||
```
|
||||
50 12 * * 1-5 /home/ubuntu/temp/chocomae-peaktime-monitoring.sh
|
||||
50 12 * * 1-5 /home/ubuntu/temp/apache-peak.sh >> /home/ubuntu/temp/apache-peak.cron.log 2>&1
|
||||
0 0 * * 1 find /home/ubuntu/temp \( -name "vmstat_*.log" -o -name "apache_*.log" \) -mtime +30 -delete
|
||||
```
|
||||
|
||||
수집 컬럼: `time busy idle K W R total_accesses db_conn db_max db_total`
|
||||
|
||||
> - `sleep $(( 10 - $(date +%s) % 10 ))` 으로 10초 격자에 고정 — vmstat 로그와 시각이 어긋나지 않습니다.
|
||||
> - DB 조회는 `sudo -n /usr/bin/mariadb` 경유 (OS 계정 `ubuntu` 는 DB 직접 접속 권한 없음, NOPASSWD sudo 가능).
|
||||
> - `db_conn`(`Threads_connected`) 은 순간값이라 짧은 PHP 연결을 대부분 놓칩니다. 판정에는 `db_max`(`Max_used_connections`, 고수위)를 쓰세요.
|
||||
|
||||
### 4-2. 판정 기준
|
||||
|
||||
| 관측 | 판단 |
|
||||
|---|---|
|
||||
| 피크 `busy` 최대가 400에 근접 | 워커가 병목. `KeepAliveTimeout` 단축 우선 검토 |
|
||||
| `K` 가 `busy` 의 대부분이고 요청률과 무관하게 큼 | `KeepAliveTimeout` 5→2초. 워커 수요 감소, CPU 여유(0.42%)로 TLS 재핸드셰이크 흡수 가능 |
|
||||
| 피크 `busy` 최대가 100 미만 | 400은 과하지만 해가 없음. 변경 불필요 |
|
||||
| `idle=0` 샘플이 잦음 | `StartServers`/`MinSpareServers` 상향 검토 |
|
||||
| `db_max` 가 27에서 오름 | DB 연결 재평가 |
|
||||
|
||||
### 4-3. 미확인 항목
|
||||
|
||||
- [ ] 외부에서 `/server-status` 접근 차단 확인 (도메인 정정 후 재시도)
|
||||
```bash
|
||||
curl -s -o /dev/null -w 'jinaju http : %{http_code}\n' http://chocomae.jinaju.com/server-status
|
||||
curl -s -o /dev/null -w 'chocomae https: %{http_code}\n' https://www.chocomae.com/server-status
|
||||
```
|
||||
`403` 이면 정상. 리버스 프록시를 거치면 `Require local` 이 프록시 IP를 통과시킬 수 있어 실제 응답 확인이 필요합니다.
|
||||
- [ ] EC2 크레딧 모드가 Unlimited 인지 Standard 인지 (콘솔 → EC2 → 인스턴스 → 크레딧 사양, 또는 CloudWatch `CPUSurplusCreditsCharged`)
|
||||
- [ ] PHP `opcache.enable` / `memory_consumption` / `memory_limit`
|
||||
```bash
|
||||
grep -rhE '^\s*(memory_limit|opcache\.enable|opcache\.memory_consumption)' /etc/php/*/apache2/php.ini /etc/php/*/apache2/conf.d/
|
||||
```
|
||||
- [ ] 피크 시각 자식 프로세스 PSS 재측정 (유휴 2MB 가 아니라 실제 값)
|
||||
|
||||
---
|
||||
|
||||
## 5. 피크 측정 결과 (2026-09-17)
|
||||
|
||||
원본: [result/peaktime/apache_20260917-1250.log](result/peaktime/apache_20260917-1250.log), [result/peaktime/vmstat_20260917-1250.log](result/peaktime/vmstat_20260917-1250.log)
|
||||
측정 구간 12:50:01~14:59:50, 10초 간격 780샘플.
|
||||
|
||||
### 5-1. 요약
|
||||
|
||||
| 항목 | 값 | 상한 대비 |
|
||||
|---|---|---|
|
||||
| **busy 워커 최대** | **204** (13:54:00) | `MaxRequestWorkers` 400의 **51%** |
|
||||
| 자식 프로세스 최대 (busy+idle) | 230 | `ServerLimit` 400의 57.5% |
|
||||
| busy 평균 | 52.9 | |
|
||||
| busy ≥ 100 샘플 | 110개 (14.1%) | |
|
||||
| busy ≥ 150 샘플 | 50개 (6.4%) | |
|
||||
| busy ≥ 200 샘플 | 3개 | |
|
||||
| `K`(KeepAlive 대기) 최대 | 152 (13:52:50) | **busy 의 69%** |
|
||||
| `W`(전송) 최대 / 평균 | 4 / 1.06 | |
|
||||
| `idle=0` 샘플 | 39개 (5.0%) | |
|
||||
| 요청률 최대 | **132.4 req/s** (14:01:40) | 평균 22.3 req/s |
|
||||
| DB 신규 연결 최대 | 31.7 conn/s | 평균 8.1 conn/s |
|
||||
| `Max_used_connections` | **27** (변동 없음) | `max_connections` 151의 18% |
|
||||
|
||||
같은 시각 vmstat:
|
||||
|
||||
| 항목 | 값 |
|
||||
|---|---|
|
||||
| us+sy 평균 / p95 / 최대 | 2.14% / 5% / **9%** |
|
||||
| 크레딧 베이스라인(20%) 초과 샘플 | **0개** |
|
||||
| steal 평균 / 최대 | 0.000% / **0%** |
|
||||
| swpd / si / so | 0 / 0 / 0 |
|
||||
| free 최소 / cache 평균 | 396MB / 2,455MB |
|
||||
|
||||
### 5-2. 시간대별 추이
|
||||
|
||||
수업 교시에 맞춰 뚜렷한 파형이 나옵니다.
|
||||
|
||||
| 구간 | busy 평균 | busy 최대 | K 평균 | req/s 평균 |
|
||||
|---|---|---|---|---|
|
||||
| 12:50 | 13.3 | 25 | 8.0 | 7.3 |
|
||||
| 13:00 | 17.5 | 32 | 9.4 | 6.2 |
|
||||
| 13:10 | 4.6 | 16 | 1.8 | 0.8 |
|
||||
| 13:20 | 4.3 | 14 | 2.1 | 1.3 |
|
||||
| 13:30 | 10.3 | 26 | 5.4 | 5.5 |
|
||||
| 13:40 | 46.9 | 94 | 33.6 | 33.0 |
|
||||
| **13:50** | **155.9** | **204** | **111.6** | **66.9** |
|
||||
| 14:00 | 115.2 | 176 | 79.7 | 46.6 |
|
||||
| 14:10 | 52.9 | 84 | 36.2 | 16.9 |
|
||||
| 14:20 | 65.7 | 106 | 46.0 | 26.1 |
|
||||
| 14:30 | 42.8 | 79 | 30.6 | 15.9 |
|
||||
| 14:40 | 83.4 | 121 | 56.9 | 33.3 |
|
||||
| 14:50 | 74.5 | 120 | 50.9 | 29.6 |
|
||||
|
||||
최대 부하 구간(13:50~14:00)은 busy 평균 156 / 최대 204, K 평균 112, 67 req/s 입니다.
|
||||
|
||||
> 피크 요청률 132 req/s 는 4일 누적 평균 3.55 req/s 의 **37배**입니다.
|
||||
> 누적 평균으로 용량을 계산하면 안 되는 이유가 이 숫자입니다.
|
||||
|
||||
### 5-3. 워커 수요 모델 (780샘플 회귀)
|
||||
|
||||
| 관계 | 회귀식 | 상관계수 |
|
||||
|---|---|---|
|
||||
| 요청률 → `K` | `K = 1.28 × req/s + 7.9` | 0.862 |
|
||||
| 요청률 → `busy` | `busy ≈ 1.74 × req/s` | 0.860 |
|
||||
|
||||
**`K` 는 요청률에 선형 비례합니다.** 9/16 저녁 샘플 7개로 "비례하지 않는다"고 본 것은 오판이었습니다.
|
||||
|
||||
`KeepAliveTimeout` 이 5초인데 계수가 1.28 이라는 것은, 연결 하나가 평균 **약 3.9개 요청**을 처리하고 끊긴다는 뜻입니다(5 ÷ 1.28). `MaxKeepAliveRequests 100` 설정 대비로는 재사용률이 낮지만, 재사용 자체는 작동하고 있습니다.
|
||||
|
||||
이 모델로 상한 도달점을 계산하면:
|
||||
|
||||
```
|
||||
현재 (KeepAliveTimeout 5초): 400 워커 ÷ 1.74 = 약 230 req/s 에서 포화
|
||||
9/17 실측 피크 = 132 req/s
|
||||
→ 여유 약 1.74배
|
||||
```
|
||||
|
||||
### 5-4. 판정
|
||||
|
||||
| 항목 | 판정 |
|
||||
|---|---|
|
||||
| `MaxRequestWorkers 400` | ✅ **적정. 유지.** 피크 51% 사용 |
|
||||
| `max_connections 151` | ✅ 적정. 고수위 27 (18%) |
|
||||
| CPU / 메모리 / steal | ✅ 전부 여유. 피크에도 us+sy 최대 9%, steal 0% |
|
||||
| `KeepAliveTimeout 5` | ⚠️ 워커의 69%를 소비. 여유가 1.74배뿐이므로 성장 대비 검토 대상 |
|
||||
| `idle=0` 5.0% | ⚠️ 예비 워커 소진 구간 존재. `MinSpareServers` 검토 대상 |
|
||||
|
||||
**120으로 낮췄다면 피크에 요청이 큐에 쌓였습니다.** 실측 204 > 120 이고, busy≥150 샘플이 50개(6.4%)였습니다. 4월 분석의 50은 더 말할 것도 없습니다. `MaxRequestWorkers 400` 은 근거 있는 설정이었습니다.
|
||||
|
||||
---
|
||||
|
||||
## 6. 권고
|
||||
|
||||
### 6-1. 지금 할 것 — 없음 (필수 변경 사항 없음)
|
||||
|
||||
모든 지표가 상한 대비 여유입니다. 서비스에 문제가 없으므로 긴급히 바꿀 설정은 없습니다.
|
||||
|
||||
### 6-2. 선택 — 성장 대비 (트래픽 1.7배 이상 증가가 예상될 때)
|
||||
|
||||
**A. `KeepAliveTimeout` 5초 → 2초**
|
||||
|
||||
```apache
|
||||
KeepAliveTimeout 2
|
||||
```
|
||||
|
||||
`K` 계수가 1.28 → 약 0.51 로 줄어 `busy ≈ 0.97 × req/s` 가 됩니다.
|
||||
|
||||
| | 포화 요청률 | 9/17 피크 대비 여유 |
|
||||
|---|---|---|
|
||||
| 현재 (5초) | 약 230 req/s | 1.74배 |
|
||||
| 변경 후 (2초) | 약 410 req/s | **3.1배** |
|
||||
|
||||
메모리도 DB 연결도 늘지 않고 여유만 1.8배가 됩니다. 비용은 TCP·TLS 재핸드셰이크 증가인데, 피크 CPU 가 us+sy 최대 9% 라 충분히 흡수됩니다.
|
||||
|
||||
**B. `MaxConnectionsPerChild` 0 → 10000**
|
||||
|
||||
```apache
|
||||
MaxConnectionsPerChild 10000
|
||||
```
|
||||
|
||||
자식 프로세스를 영원히 재활용하지 않는 현재 설정은 mod_php 누수가 누적됩니다. 위험도 낮은 위생 조치입니다.
|
||||
|
||||
**C. `MinSpareServers` 검토**
|
||||
|
||||
`idle=0` 샘플이 39개(5.0%)이고 그때 busy 평균이 89였습니다. 예비 워커가 떨어지면 다음 요청은 fork 를 기다립니다. 13:40~13:50 구간처럼 busy 가 10 → 204 로 급등할 때 특히 영향이 있습니다.
|
||||
|
||||
현재 값을 먼저 확인해야 합니다.
|
||||
|
||||
```bash
|
||||
grep -E 'MinSpareServers|MaxSpareServers' /etc/apache2/mods-enabled/mpm_prefork.conf
|
||||
```
|
||||
|
||||
Debian 기본값(5 / 10)이라면 피크 busy 평균 53 에 비해 지나치게 작습니다. 20 / 50 정도로 올리면 fork 급증 구간이 완만해집니다.
|
||||
|
||||
적용은 무중단입니다.
|
||||
|
||||
```bash
|
||||
sudo cp /etc/apache2/mods-available/mpm_prefork.conf /etc/apache2/mods-available/mpm_prefork.conf.bak-$(date +%Y%m%d)
|
||||
sudo apache2ctl configtest && sudo systemctl reload apache2
|
||||
```
|
||||
|
||||
### 6-3. 재측정
|
||||
|
||||
설정을 바꾸면 같은 스크립트로 하루 더 측정해 `K` 계수가 예상대로 내려갔는지 확인하세요. cron 은 평일 12:50 에 계속 돌고 있습니다.
|
||||
|
||||
### 6-4. 남은 확인 항목
|
||||
|
||||
- [ ] EC2 크레딧 모드 (Unlimited / Standard) — 9/17 steal 0%, 베이스라인 초과 0샘플이라 실질 위험은 낮음
|
||||
- [ ] 외부에서 `/server-status` 접근 차단 확인
|
||||
- [ ] PHP `opcache.enable` 여부
|
||||
Reference in New Issue
Block a user