🚀 모니터링과 부하테스트 입문
📌 강의 목표
이 특강이 끝나면 여러분은 다음을 할 수 있게 됩니다:
- 부하테스트가 왜 필요한지, 어떤 종류가 있는지 설명할 수 있다.
- TPS, 응답시간(p95/p99), 에러율 같은 핵심 지표를 읽고 해석할 수 있다.
- K6로 간단한 부하테스트 스크립트를 작성하고 실행할 수 있다.
- nGrinder가 무엇이고 K6와 어떻게 다른지 비교할 수 있다.
- 부하테스트 지표와 시스템 지표(CPU, 메모리, JVM/GC, DB)를 함께 보고 병목을 추론할 수 있다.
1. 왜 부하테스트와 모니터링이 필요한가
개발 환경에서 잘 동작하던 API가 운영에서 사용자가 몰리면 느려지거나 죽는 일이 흔합니다. 이유는 단순합니다. 개발 중에는 보통 혼자(동시 사용자 1명) 테스트하기 때문입니다.
실제 서비스는 수백, 수천 명이 동시에 같은 자원(스레드, DB 커넥션, 메모리)을 두고 경쟁합니다.
모니터링은 그 과정과 운영 중에 "시스템 내부에서 무슨 일이 일어나는지"를 숫자로 보는 작업입니다.
이 둘은 항상 같이 갑니다. 부하를 주는 쪽(부하테스트 도구)에서 나오는 지표와, 부하를 받는 쪽(서버)에서 나오는 지표를 짝지어 봐야 원인을 알 수 있기 때문입니다.
2. 핵심 개념과 용어
부하테스트 결과를 읽으려면 먼저 용어를 정확히 알아야 합니다. 입문자가 가장 자주 헷갈리는 것들입니다.
2.1 부하를 표현하는 용어
VU (Virtual User, 가상 사용자): 동시에 요청을 보내는 가상의 사용자 수. K6에서는 VUs, nGrinder에서는 Vuser라고 부릅니다. VU 1명은 "요청 보내고 응답 받으면 다음 요청을 보내는" 행동을 반복합니다.
동시 사용자(Concurrency)와 초당 요청 수(RPS)는 다릅니다. VU 100명이라고 해서 초당 100건이 아닙니다. 한 요청이 0.2초 걸리면 VU 1명은 초당 약 5건을 보낼 수 있으므로, VU 100명은 초당 약 500건을 만듭니다.
예: VU 50개, 평균 응답시간 100ms → RPS = 50 × (1 / 0.1) = 500 RPS
2.2 처리량을 표현하는 용어
- Throughput(처리량): 단위 시간당 처리한 요청 수
- TPS (Transactions Per Second): 초당 처리한 트랜잭션(요청) 수. 시스템의 "처리 능력"을 나타내는 가장 중요한 지표. 높을수록 좋다.
- RPS (Requests Per Second): 초당 요청 수. TPS와 거의 같은 의미로 쓰이지만, 한 트랜잭션이 여러 HTTP 요청으로 구성되면 달라질 수 있다.
2.3 응답시간(Latency)을 표현하는 용어
Latency / Response Time(응답시간): 요청을 보내고 응답을 받기까지 걸린 시간. 낮을수록 좋다.
예를 들어 응답시간이 [100ms, 100ms, 100ms, 100ms, 5000ms]라면 평균은 1080ms입니다. 평균만 보면 "1초쯤 걸리네"라고 생각하지만, 실제로는 5명 중 1명이 5초를 기다린 것입니다. 이 1명이 가장 화가 난 사용자이고, 이런 사용자가 이탈합니다.
그래서 백분위수(Percentile)를 봅니다.
| 백분위수 | 의미 | 실무 활용 |
|---|---|---|
| p50 (median) | 절반의 요청이 이 시간 안에 처리됨 | 중앙값 확인용 |
| p95 | 95%의 요청이 이 시간 안에 처리됨 | 느린 5%의 경계 — SLO 기준 |
| p99 | 99%의 요청이 이 시간 안에 처리됨 | 가장 느린 1%의 경계 |
실무에서는 보통 p95, p99를 SLO(Service Level Objectives / 서비스 수준 목표)의 기준으로 삼습니다.
2.4 안정성을 표현하는 용어
Error Rate(에러율): 전체 요청 중 실패한 요청의 비율. HTTP 5xx, 타임아웃, 커넥션 거부 등이 실패로 잡힙니다. 부하가 올라가면서 에러율이 치솟는 지점이 바로 시스템의 한계점입니다.
2.5 용어 요약
| 용어 | 의미 | 좋은 방향 |
|---|---|---|
| VU / Vuser | 동시 가상 사용자 수 | (부하의 크기, 조절 대상) |
| TPS / RPS | 초당 처리 요청 수 | 높을수록 좋음 |
| p95 / p99 응답시간 | 느린 쪽 응답시간 | 낮을수록 좋음 |
| Error Rate | 실패 비율 | 0%에 가깝게 |
3. 부하테스트의 종류
같은 도구라도 "어떤 패턴으로 부하를 주는가"에 따라 목적이 다릅니다.
| 테스트 종류 | 설명 | 목적 |
|---|---|---|
| Smoke Test | VU 1~2명으로 아주 가볍게 | 스크립트 정상 동작 여부 사전 점검 |
| Load Test | 예상 피크 트래픽 재현 | 목표 동시 사용자 수에서 기준 만족 여부 검증 |
| Stress Test | 부하를 점점 올려 한계점 탐색 | "최대 몇 명까지 버티는가" 확인 |
| Spike Test | 짧은 시간에 트래픽 급증 | 급증/급감 시 시스템 반응 확인 |
| Soak Test | 중간 부하를 수 시간 유지 | 메모리 누수, 커넥션 누수 탐지 |
4. K6 소개
K6는 Grafana Labs가 개발하는 오픈소스 부하테스트 도구입니다. Go로 만들어졌고, 테스트 스크립트는 JavaScript로 작성합니다. 현재도 활발히 개발되고 있습니다.
- CLI 기반으로 가볍고 빠름 —
k6 run script.js한 줄로 실행 - 스크립트가 JavaScript라 Git 버전 관리하기 좋음
- Prometheus, Grafana, InfluxDB 등으로 결과 내보내기 가능
- CI/CD 파이프라인 자동화에 적합
4.1 설치
# macOS
brew install k6
# Windows (Chocolatey)
choco install k6
# Linux (Ubuntu/Debian)
sudo gpg --no-default-keyring \
--keyring /usr/share/keyrings/k6-archive-keyring.gpg \
--keyserver hkp://keyserver.ubuntu.com:80 \
--recv-keys C5AD17C747E3415A3642D57D77C6C491FC6F0692
echo "deb https://dl.k6.io/deb stable main" \
| sudo tee /etc/apt/sources.list.d/k6.list
sudo apt-get update && sudo apt-get install k6
# Docker
docker run --rm -i grafana/k6 run - < script.js
4.2 가장 기본적인 스크립트
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 10, // 동시 가상 사용자 10명
duration: '30s', // 30초 동안 실행
};
export default function () {
const res = http.get('http://localhost:8080/api/products');
// 응답 검증: 상태코드가 200인가
check(res, {
'status is 200': (r) => r.status === 200,
});
sleep(1); // 다음 요청까지 1초 대기 (실제 사용자 행동 모사)
}
4.3 단계적으로 부하를 올리는 스크립트 (Stress Test)
import http from 'k6/http';
import { check } from 'k6';
export const options = {
stages: [
{ duration: '1m', target: 50 }, // 1분에 VU 50명까지 증가
{ duration: '2m', target: 50 }, // 2분간 50명 유지
{ duration: '1m', target: 200 }, // 1분에 200명까지 증가
{ duration: '2m', target: 200 }, // 2분간 200명 유지
{ duration: '1m', target: 0 }, // 1분에 걸쳐 종료
],
};
export default function () {
const res = http.get('http://localhost:8080/api/products');
check(res, { 'status is 200': (r) => r.status === 200 });
}
4.4 기준 자동화 (Thresholds) — 현업 필수!
K6의 강력한 기능 중 하나는 Thresholds입니다. SLO를 코드로 박아두면, 기준 미달 시 테스트가 자동으로 실패(exit code ≠ 0)합니다. CI에서 성능 회귀를 잡는 데 유용합니다.
export const options = {
vus: 50,
duration: '1m',
thresholds: {
// 95%가 200ms 이내여야 통과
http_req_duration: ['p(95)<200'],
// 에러율 1% 미만이어야 통과
http_req_failed: ['rate<0.01'],
},
};
4.5 현업 고급 패턴 — Arrival Rate (RPS 기반)
현업에서는 VU 기반보다 초당 몇 건을 처리해야 하는가에 집중하는 RPS 기반 테스트가 선호됩니다.
import http from 'k6/http';
export const options = {
scenarios: {
// 평소 트래픽 (100 RPS)
baseline: {
executor: 'constant-arrival-rate',
rate: 100,
timeUnit: '1s',
duration: '2m',
preAllocatedVUs: 20,
},
// 피크 시간 (100 → 500 RPS 점진 증가)
peak: {
executor: 'ramping-arrival-rate',
startTime: '2m',
startRate: 100,
timeUnit: '1s',
stages: [
{ target: 500, duration: '3m' },
{ target: 500, duration: '5m' },
{ target: 0, duration: '1m' },
],
preAllocatedVUs: 100,
maxVUs: 200,
},
},
thresholds: {
http_req_duration: ['p(95)<300', 'p(99)<500'],
http_req_failed: ['rate<0.01'],
},
};
export default function () {
http.get('http://test.k6.io/');
}
5. nGrinder 소개
nGrinder는 네이버가 The Grinder를 기반으로 만든 오픈소스 부하테스트 플랫폼입니다. 국내 기업 환경에서 오래 사용되어 한국어 자료가 풍부하고, 웹 GUI 기반이라 비개발 직군도 접근하기 쉽다는 장점이 있습니다.
5.1 구조 (K6와 가장 큰 차이)
| 컴포넌트 | 역할 |
|---|---|
| Controller | 웹 UI 제공. 스크립트 작성, 테스트 설정, 실행, 리포트 담당 |
| Agent | 실제로 부하를 생성하는 부분. 큰 부하가 필요하면 여러 대로 분산 |
| Target | 부하를 받는 우리 서버 (Spring Boot 애플리케이션) |
5.2 스크립트 (Groovy 예시)
// Groovy 스크립트 예시 (핵심 부분만)
import static net.grinder.script.Grinder.grinder
import HTTPClient.HTTPResponse
import net.grinder.plugin.http.HTTPRequest
class TestRunner {
public static HTTPRequest request = new HTTPRequest()
@Test
public void test() {
HTTPResponse result = request.GET("http://localhost:8080/api/products")
assertThat(result.statusCode, is(200))
}
}
5.3 사용 흐름
- 컨트롤러 WAR 실행 → 웹 브라우저로 접속
- 에이전트를 다운로드해 부하 생성기로 등록
- 웹 UI에서 대상 URL, Vuser 수, 실행 시간 설정
- 실행하면 TPS, 응답시간, 에러를 실시간 그래프로 확인
- 종료 후 리포트(TPS 추이, 평균/최대 응답시간 등) 확인
6. K6 vs nGrinder 비교
| 항목 | K6 | nGrinder |
|---|---|---|
| 개발/관리 | Grafana Labs, 활발히 개발 중 | 네이버, 2025년 9월 아카이브 |
| 인터페이스 | CLI 중심 | 웹 GUI 중심 |
| 스크립트 언어 | JavaScript | Groovy / Jython |
| 설치/구성 | 단일 바이너리, 가벼움 | Controller + Agent 구성 필요 |
| 분산 부하 | 가능 (k6 Cloud 또는 직접 구성) | 에이전트 다중화로 쉽게 분산 |
| 코드 관리(Git) | 매우 적합 | 상대적으로 불편 |
| CI/CD 연동 | 매우 적합 | 상대적으로 불편 |
| 시각화 | Grafana 연동 강력 | 자체 리포트 내장 |
| 진입 장벽 | 코드 작성 필요 | GUI로 쉽게 시작 |
| 한국어 자료 | 보통 | 풍부 |
6.1 도구 선택 가이드 (2024년 동향)
| 도구 | 적합한 팀 | 핵심 장점 |
|---|---|---|
| K6 | 개발자 중심, DevOps 팀 | CI/CD 친화적, 효율적 리소스 사용 |
| JMeter | QA 팀, 레거시 환경 | 방대한 플러그인, GUI 풍부 |
| Locust | Python 팀 | Python 스크립트, 분산 테스트 |
7. 부하테스트 지표 읽기
K6 실행 후 출력되는 요약 결과를 해석하는 방법입니다.
http_req_duration..: avg=120ms min=15ms med=98ms max=2.1s p(90)=210ms p(95)=350ms
http_req_failed....: 0.50% ✓ 12 ✗ 2388
http_reqs..........: 2400 80.1/s
vus................: 50 min=0 max=50
| 지표 | 값 | 의미 |
|---|---|---|
| avg | 120ms | 평균은 괜찮아 보이지만... |
| p(95) | 350ms | 느린 5%는 350ms 초과 — "p95 200ms" 목표라면 미달! |
| max | 2.1s | 가장 느린 요청은 2.1초 |
| http_req_failed | 0.50% | 약간의 에러 발생 — 원인 확인 필요 |
| http_reqs | 80.1/s | 사실상 TPS/RPS |
해석 순서
- 에러율 먼저 — 에러가 많으면 응답시간 숫자는 의미 없음 (실패한 요청은 빨리 끝나서 평균을 왜곡함)
- p95/p99 응답시간 — 평균이 아니라 백분위수로 판단
- TPS 확인 — VU를 올렸는데 TPS가 그대로면 그 지점이 포화 상태
8. APM과 시스템 지표
부하테스트 도구의 숫자는 "밖에서 본 결과"입니다. 왜 느린지 알려면 "서버 안"을 봐야 합니다. Spring Boot에서는 Actuator + Micrometer + Prometheus + Grafana 조합이 표준입니다.
8.1 Spring Boot Actuator 설정
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'io.micrometer:micrometer-registry-prometheus'
}
management:
endpoints:
web:
exposure:
include: health, info, prometheus, metrics
metrics:
tags:
application: ${spring.application.name}
environment: ${spring.profiles.active}
8.2 꼭 확인해야 할 서버 지표
| 지표 | 확인 방법 | 병목 증상 |
|---|---|---|
| CPU 사용률 | node_cpu_usage |
100% 유지 → CPU 바운드 연산 과다 |
| JVM Heap | jvm_memory_used_bytes |
우상향 추세 → 메모리 누수 의심 |
| GC pause | jvm_gc_pause_seconds |
빈번/장시간 일시 정지 → 응답시간 튀는 원인 |
| 스레드 풀 | tomcat.threads.busy |
모두 사용 중 → 새 요청 대기 |
| HikariCP | hikaricp.* |
pending 증가 → 풀 고갈 또는 쿼리 느림 |
8.3 HikariCP 커넥션 풀 사이징
# 권장 공식
connections = (core_count * 2) + effective_spindle_count
# 4코어 + SSD
4 * 2 + 0 = 8 connections
# 4코어 + HDD 2개
4 * 2 + 2 = 10 connections
8.4 증상 ↔ 원인 매핑
| 부하테스트 쪽(밖) 증상 | 서버 쪽(안) 확인 지표 |
|---|---|
| 응답시간이 길어짐 | CPU, GC, DB 커넥션 대기, 스레드 풀 |
| 에러율 급증(5xx) | 예외 로그, 스레드 풀 고갈, 커넥션 타임아웃 |
| TPS가 더 안 오름 | CPU 포화 여부, DB가 한계인지 |
| 시간이 갈수록 느려짐 | Heap 우상향(메모리 누수), 커넥션 누수 |
9. 병목 진단 실습 (케이스 스터디)
케이스 A: 평균은 괜찮은데 p99가 매우 나쁨
// 증상
avg 90ms, p99 1800ms. 에러는 거의 없음.
// 관찰
Grafana에서 응답시간이 주기적으로 튄다.
그 시점에 GC pause 그래프도 같이 튄다.
// 추론
GC 멈춤이 일부 요청을 길게 만든다.
// 조치 방향
Heap 크기, GC 알고리즘 점검.
불필요한 객체 생성 줄이기.
케이스 B: VU를 올려도 TPS가 안 오름
// 증상
VU 50 → 100으로 올렸는데 TPS는 80 → 82로 그대로.
p95는 2배.
// 관찰
서버 CPU는 40%로 한가함.
HikariCP pending connection이 계속 쌓임.
// 추론
CPU가 한가한데 막힌다 = DB 커넥션 풀 병목.
요청들이 커넥션을 기다리는 중.
// 조치 방향
커넥션 풀 크기 조정, 느린 쿼리 최적화(인덱스), N+1 쿼리 제거.
케이스 C: 부하 시작 직후 에러율 급증
// 증상
부하를 주자마자 5xx가 쏟아짐.
// 관찰
톰캣 스레드 풀이 즉시 꽉 참.
로그에 connection timeout.
// 추론
처리 용량 대비 동시 요청이 너무 많거나,
다운스트림(외부 API/DB)이 막혀 스레드가 점유됨.
// 조치 방향
스레드 풀/타임아웃 설정 점검, 다운스트림 응답 확인.
케이스 D: Soak 테스트에서 시간이 갈수록 느려짐
// 증상
처음엔 100ms, 2시간 뒤 1500ms. 부하는 일정.
// 관찰
Heap 사용량이 계속 우상향.
GC를 해도 회수 안 됨.
// 추론
메모리 누수 (캐시 무한 증가, 닫지 않은 리소스 등).
// 조치 방향
힙 덤프 분석, 누수 객체 추적, 리소스 close 확인.
10. 마무리 체크리스트
- 응답시간은 평균이 아니라 p95/p99로 본다
- 지표는 항상 에러율 → 응답시간 → TPS 순으로 읽는다
- 부하테스트 도구(밖)와 서버 지표(안)를 짝지어 원인을 추론한다
- VU를 올려도 TPS가 안 오르면 그 지점이 시스템의 한계다
- CPU가 한가한데 느리면 대기(DB 커넥션, 락, I/O)를 의심한다
- 메모리 누수는 Soak 테스트와 Heap 그래프 우상향으로 잡는다
- 새로 배운다면 K6를 메인으로, nGrinder는 GUI 대안으로 이해한다
11. 다음 프로젝트에 바로 적용하기 — 현업 실천 가이드
다음 프로젝트에서 실제로 어떻게 적용할지가 중요하다.
현업에서 자주 쓰이는 실천 방법들을 단계별로 정리했습니다.
11.1 SLO부터 먼저 정하고 시작하기
부하테스트를 돌리기 전에 가장 먼저 해야 할 일은 "얼마나 빨라야 합격인가"를 팀이 합의하는 것입니다. 기준 없이 돌리면 결과를 봐도 "이게 좋은 건지 나쁜 건지" 판단할 수 없습니다.
// 팀이 합의한 SLO를 thresholds로 고정
export const options = {
thresholds: {
http_req_duration: ['p(95)<300', 'p(99)<500'],
http_req_failed: ['rate<0.01'],
},
};
// 이 기준을 통과하지 못하면 k6가 exit code 1을 반환
// → CI 파이프라인에서 빌드 실패로 잡을 수 있음
11.2 개발 초기부터 Actuator + Prometheus 붙이기
모니터링 스택은 나중에 붙이면 붙일수록 귀찮아집니다. 프로젝트 시작 시점에 의존성 두 줄만 추가해두면 나중에 Grafana 대시보드 연동이 훨씬 수월합니다. 특히 spring.application.name 태깅을 초반에 잡아두지 않으면, 마이크로서비스가 늘어났을 때 어떤 서비스의 지표인지 구분이 안 되는 상황이 생깁니다.
spring:
application:
name: my-service # 반드시 고유한 이름으로
management:
endpoints:
web:
exposure:
include: health, prometheus, metrics
metrics:
tags:
application: ${spring.application.name}
env: ${spring.profiles.active:local}
11.3 Smoke Test를 PR 규칙으로 만들기
현업에서 부하테스트가 흐지부지되는 가장 큰 이유는 "배포 직전에 한 번 돌리고 끝"이기 때문입니다. 팀에서 지속적으로 운영하려면 GitHub Actions 같은 CI에 Smoke Test를 연결해두고 PR마다 자동으로 실행되게 만드는 게 효과적입니다. Smoke Test는 VU 1~2명으로 30초면 충분하니 CI 시간도 크게 늘지 않습니다.
name: Smoke Test
on: [pull_request]
jobs:
smoke:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Start app
run: ./gradlew bootRun &
# 앱 기동 대기
- name: Run K6 Smoke Test
uses: grafana/k6-action@v0.3.1
with:
filename: k6/smoke.js
# thresholds 미달 시 자동으로 step 실패
11.4 부하테스트 대상 API 우선순위 정하기
모든 API를 다 테스트하려고 하면 오히려 아무것도 제대로 못 합니다. 현업에서는 다음 기준으로 우선순위를 정합니다.
| 우선순위 | 대상 | 이유 |
|---|---|---|
| 🔴 높음 | 로그인, 메인 피드, 결제, 검색 | 트래픽이 가장 많이 몰리는 경로 |
| 🟡 중간 | 상품 상세, 주문 목록 조회 | DB 쿼리 복잡도가 높아 병목 가능성 있음 |
| 🟢 낮음 | 설정 변경, 단순 CRUD | 트래픽 적고 로직 단순 |
11.5 로컬에서 돌릴 때 주의할 점
로컬 머신에서 K6를 돌리면 테스트 도구 자체가 CPU와 메모리를 잡아먹어서 결과가 왜곡될 수 있습니다. 특히 VU가 50명을 넘어가면 로컬 결과를 그대로 믿으면 안 됩니다. 현업에서는 테스트 서버(또는 CI 에이전트)와 애플리케이션 서버를 물리적으로 분리해서 실행하는 것이 기본입니다.
11.6 Grafana 대시보드를 미리 구성해두기
부하테스트를 돌리면서 Grafana 없이 터미널 숫자만 보면 놓치는 게 많습니다. 특히 "GC pause가 언제 일어났는가"는 숫자가 아닌 그래프에서만 패턴이 보입니다. Grafana Labs가 공식 제공하는 Spring Boot 대시보드(ID: 11378)와 K6 대시보드(ID: 2587)를 Import해두면 처음부터 쓸만한 대시보드를 빠르게 세팅할 수 있습니다.
# Grafana UI에서 Dashboards → Import → ID 입력
11378 # JVM (Micrometer) — Spring Boot 전용
1860 # Node Exporter Full — 서버 OS 지표
2587 # K6 Load Testing Results
9628 # PostgreSQL Database — DB 사용 시
11.7 부하테스트 결과를 문서로 남기는 습관
한 번 돌리고 끝나는 테스트는 팀에 아무 자산도 남기지 않습니다. 현업에서는 테스트 결과를 간단한 포맷으로 Confluence, Notion, 또는 PR 코멘트에 남깁니다. 다음 릴리스 때 "이번 변경 후 TPS가 얼마나 바뀌었는가"를 비교할 수 있어야 의미가 있습니다.
📅 테스트 일시: 2026-06-02
🎯 대상 API: GET /api/products
👥 VU: 50명 / 시간: 3분
📊 TPS: 312 req/s
⏱️ p95: 187ms / p99: 290ms
❌ 에러율: 0.1%
🔍 특이사항: HikariCP pending 일시적 증가 (max 3개), 무해 수준
11.8 운영 전 체크리스트 — "출시 전 반드시 돌릴 것"
기능 개발이 끝나고 배포 전에 팀 내에서 공유할 수 있는 최소한의 체크포인트입니다. 처음부터 거창하게 하려고 하면 실천이 어렵습니다. 이 네 가지만 습관으로 만들어도 운영에서 발생하는 대부분의 성능 이슈를 사전에 잡을 수 있습니다.
- Smoke Test 통과 확인 (스크립트가 정상 동작하는가)
- 목표 트래픽 기준 Load Test 실행 후 SLO 만족 여부 확인
- 부하 중 HikariCP pending, 스레드 풀 포화 여부 Grafana로 확인
- 테스트 결과 TPS / p95 / 에러율 수치를 PR 또는 노션에 기록
📚 보충 자료
부록 A. 자주 쓰는 K6 명령어
# 기본 실행
k6 run script.js
# CLI 옵션 직접 지정
k6 run --vus 50 --duration 30s script.js
# 결과를 JSON으로 저장 (사후 분석)
k6 run --out json=result.json script.js
# Prometheus로 전송 (실시간 모니터링)
k6 run --out experimental-prometheus-rw script.js
# Docker로 실행
docker run --rm -i grafana/k6 run \
-e TARGET_URL=http://localhost:8080 \
- < script.js
부록 B. K6 주요 내장 지표
| 지표 | 의미 |
|---|---|
http_req_duration |
요청 전체 응답시간 (DNS+연결+응답 포함) |
http_req_waiting |
서버 처리 대기 시간 (TTFB) |
http_req_failed |
실패한 요청 비율 |
http_reqs |
총 요청 수 + 초당 요청 수 |
vus / vus_max |
현재/최대 가상 사용자 수 |
부록 C. SLO/SLI/SLA 개념
SLO: 달성하려는 목표 (예: p95 < 200ms)
SLA: 고객과 약속한 수준 (SLO 위반 시 패널티 발생)
부록 D. JVM GC 종류
| GC | 특징 | 적합한 상황 |
|---|---|---|
| Serial GC | 단일 스레드, 간단 | Heap < 100MB 소규모 |
| Parallel GC | 멀티 스레드, 처리량 중심 | 배치 처리, 백그라운드 jobs |
| G1 GC | 균형 잡힌 지연/처리량 | Heap ≥ 6GB, latency-sensitive |
| ZGC / Shenandoah | 초저지연 (< 10ms) | 대형 Heap (≥ 100GB) |
부록 E. 현업 통합 파이프라인 (2024년 동향)
- K6로 부하테스트 실행
- Prometheus가 K6 메트릭 + 서버 메트릭 통합 수집
- Grafana에서 실시간 대시보드 (테스트 결과 + APM)
- SLO 기반 Alertmanager로 Slack/PagerDuty 알림
- OpenTelemetry로 마이크로서비스 간 추적
부록 F. 참고 링크
- K6 공식 문서: grafana.com/docs/k6
- K6 GitHub: github.com/grafana/k6
- nGrinder 공식 페이지: naver.github.io/ngrinder
- Spring Boot Actuator 문서: docs.spring.io
- Google SRE Book - SLO: sre.google
- HikariCP 풀 사이징: HikariCP Wiki
'스파르타 심화 과정' 카테고리의 다른 글
| RAG 이해하기 (0) | 2026.06.09 |
|---|---|
| CQRS (0) | 2026.05.26 |
| spring 과제 (0) | 2026.04.21 |
| 4/20 Spring 기초(2) 특강 (0) | 2026.04.20 |
| spring 특강 1 (0) | 2026.04.20 |
