|
| 1 | +# 모니터링 + k6 부하테스트 가이드 |
| 2 | + |
| 3 | +이 문서는 현재 프로젝트 백엔드(Spring Boot) 기준으로, 다음 두 가지를 빠르게 적용/운영하기 위한 정리입니다. |
| 4 | + |
| 5 | +- 모니터링: `Actuator + Prometheus + Grafana` |
| 6 | +- 로컬 부하테스트: `k6` |
| 7 | + |
| 8 | +## 1. 현재 백엔드 준비 상태 |
| 9 | + |
| 10 | +아래 항목이 코드에 반영되어 있어야 Grafana에서 메트릭을 볼 수 있습니다. |
| 11 | + |
| 12 | +- 의존성 |
| 13 | + - `org.springframework.boot:spring-boot-starter-actuator` |
| 14 | + - `io.micrometer:micrometer-registry-prometheus` |
| 15 | +- 설정 (`application-dev.yml`, `application-prod.yml`) |
| 16 | + - `management.endpoints.web.exposure.include: health, prometheus` |
| 17 | + - `management.prometheus.metrics.export.enabled: true` |
| 18 | + - `management.metrics.distribution.percentiles-histogram.http.server.requests: true` |
| 19 | +- 보안 허용 (`SecurityConfig`) |
| 20 | + - `/actuator/health` |
| 21 | + - `/actuator/prometheus` |
| 22 | + |
| 23 | +## 2. 모니터링 점검 순서 |
| 24 | + |
| 25 | +### 2.1 백엔드 메트릭 엔드포인트 확인 |
| 26 | + |
| 27 | +로컬: |
| 28 | + |
| 29 | +```bash |
| 30 | +curl -s http://localhost:8080/actuator/health |
| 31 | +curl -s http://localhost:8080/actuator/prometheus | head -n 20 |
| 32 | +``` |
| 33 | + |
| 34 | +배포: |
| 35 | + |
| 36 | +```bash |
| 37 | +curl -s http://app_blue:8080/actuator/prometheus | head -n 20 |
| 38 | +``` |
| 39 | + |
| 40 | +### 2.2 Prometheus 타겟 확인 |
| 41 | + |
| 42 | +`http://<EC2_IP>:9090/targets`에서 아래가 `UP`인지 확인합니다. |
| 43 | + |
| 44 | +- `prometheus` |
| 45 | +- `app-blue` (`app_blue:8080`) |
| 46 | +- `app-green` (`app_green:8080`) |
| 47 | + |
| 48 | +### 2.3 Grafana 데이터소스 확인 |
| 49 | + |
| 50 | +1. `http://<EC2_IP>:3000` 접속 |
| 51 | +2. `admin / password_1` 값으로 로그인 |
| 52 | +3. `Data Sources > Prometheus > Save & test` |
| 53 | + |
| 54 | +## 3. Grafana 추천 패널 (PromQL) |
| 55 | + |
| 56 | +### 3.1 트래픽 (RPS) |
| 57 | + |
| 58 | +```promql |
| 59 | +sum(rate(http_server_requests_seconds_count[1m])) |
| 60 | +``` |
| 61 | + |
| 62 | +### 3.2 평균 응답시간 (초) |
| 63 | + |
| 64 | +```promql |
| 65 | +sum(rate(http_server_requests_seconds_sum[1m])) |
| 66 | +/ |
| 67 | +sum(rate(http_server_requests_seconds_count[1m])) |
| 68 | +``` |
| 69 | + |
| 70 | +### 3.3 p95 응답시간 (초) |
| 71 | + |
| 72 | +```promql |
| 73 | +histogram_quantile( |
| 74 | + 0.95, |
| 75 | + sum(rate(http_server_requests_seconds_bucket[5m])) by (le) |
| 76 | +) |
| 77 | +``` |
| 78 | + |
| 79 | +### 3.4 5xx 비율 |
| 80 | + |
| 81 | +```promql |
| 82 | +sum(rate(http_server_requests_seconds_count{status=~"5.."}[5m])) |
| 83 | +/ |
| 84 | +sum(rate(http_server_requests_seconds_count[5m])) |
| 85 | +``` |
| 86 | + |
| 87 | +### 3.5 JVM Heap 사용량 (바이트) |
| 88 | + |
| 89 | +```promql |
| 90 | +sum(jvm_memory_used_bytes{area="heap"}) |
| 91 | +``` |
| 92 | + |
| 93 | +## 4. Node Exporter 추가 (호스트 메트릭) |
| 94 | + |
| 95 | +EC2에서 아래처럼 실행하면 호스트 CPU/메모리/디스크 지표를 수집할 수 있습니다. |
| 96 | + |
| 97 | +```bash |
| 98 | +docker run -d \ |
| 99 | + --name node_exporter \ |
| 100 | + --restart unless-stopped \ |
| 101 | + --network common \ |
| 102 | + -p 9100:9100 \ |
| 103 | + --pid="host" \ |
| 104 | + -v "/:/host:ro,rslave" \ |
| 105 | + quay.io/prometheus/node-exporter:latest \ |
| 106 | + --path.rootfs=/host |
| 107 | +``` |
| 108 | + |
| 109 | +Prometheus 설정(`prometheus.yml`)에 타겟을 추가합니다. |
| 110 | + |
| 111 | +```yaml |
| 112 | +scrape_configs: |
| 113 | + - job_name: "node" |
| 114 | + static_configs: |
| 115 | + - targets: ["node_exporter:9100"] |
| 116 | +``` |
| 117 | +
|
| 118 | +적용 후: |
| 119 | +
|
| 120 | +```bash |
| 121 | +docker restart prometheus_1 |
| 122 | +curl -s http://localhost:9090/api/v1/targets | head -c 1200 |
| 123 | +``` |
| 124 | + |
| 125 | +Node Exporter가 `UP`이면 Grafana에서 아래 지표를 사용할 수 있습니다. |
| 126 | + |
| 127 | +- `rate(node_cpu_seconds_total{mode!="idle"}[1m])` |
| 128 | +- `node_memory_MemAvailable_bytes` |
| 129 | +- `node_filesystem_avail_bytes` |
| 130 | + |
| 131 | +## 5. 로컬 k6 부하테스트 |
| 132 | + |
| 133 | +## 5.1 설치 |
| 134 | + |
| 135 | +macOS(Homebrew): |
| 136 | + |
| 137 | +```bash |
| 138 | +brew install k6 |
| 139 | +``` |
| 140 | + |
| 141 | +확인: |
| 142 | + |
| 143 | +```bash |
| 144 | +k6 version |
| 145 | +``` |
| 146 | + |
| 147 | +## 5.2 스크립트 위치 |
| 148 | + |
| 149 | +- `k6/smoke.js`: 짧은 기본 점검 |
| 150 | +- `k6/load.js`: 지속 부하 테스트 |
| 151 | +- `k6/spike.js`: 급격한 트래픽 증가 테스트 |
| 152 | + |
| 153 | +## 5.3 실행 전 환경변수 |
| 154 | + |
| 155 | +```bash |
| 156 | +export BASE_URL=http://localhost:8080 |
| 157 | +export K6_EMAIL=admin@gmail.com |
| 158 | +export K6_PASSWORD=admin1234 |
| 159 | +# 선택: 인증 시나리오에서 사용할 문제 ID |
| 160 | +export K6_PROBLEM_ID=1 |
| 161 | +``` |
| 162 | + |
| 163 | +`K6_EMAIL/K6_PASSWORD` 계정은 미리 가입되어 있어야 합니다. |
| 164 | + |
| 165 | +## 5.4 실행 명령 |
| 166 | + |
| 167 | +```bash |
| 168 | +k6 run k6/smoke.js |
| 169 | +k6 run k6/load.js |
| 170 | +k6 run k6/spike.js |
| 171 | +``` |
| 172 | + |
| 173 | +## 6. 권장 기준(초안) |
| 174 | + |
| 175 | +- `http_req_failed`: `< 1%` |
| 176 | +- 일반 조회 API `p95`: `< 700ms` |
| 177 | +- 채점 요청 API `p95`: `< 2s` (비동기 큐 진입 기준) |
| 178 | + |
| 179 | +## 7. 주의사항 |
| 180 | + |
| 181 | +- k6는 로컬 또는 별도 로드 제너레이터에서 실행하세요. |
| 182 | + - 앱 서버에서 직접 부하를 걸면 CPU/메모리 경쟁으로 결과가 왜곡될 수 있습니다. |
| 183 | +- 테스트 전/후 DB 상태를 확인하고, 운영 DB에는 직접 대량 부하를 주지 않는 것을 권장합니다. |
| 184 | +- WebSocket 배틀 시나리오는 HTTP 시나리오 안정화 후 2차로 분리해 진행하세요. |
0 commit comments