k6 부하테스트 완벽 가이드 — JavaScript로 Stress·Spike·Soak 작성
k6는 Grafana Labs가 개발한 오픈소스 부하테스트 도구입니다. JavaScript로 시나리오를 작성하고, 단일 바이너리로 실행하며, CI/CD 통합이 JMeter보다 훨씬 간단합니다.
# macOSbrew install k6
# Windows (winget)winget install k6
# Dockerdocker pull grafana/k6기본 구조
섹션 제목: “기본 구조”import http from 'k6/http';import { check, sleep } from 'k6';
// 테스트 설정export const options = { vus: 50, // 가상 사용자 수 duration: '2m', // 실행 시간 thresholds: { http_req_duration: ['p(95)<300'], // p95 300ms 이하 http_req_failed: ['rate<0.01'], // 에러율 1% 이하 },};
// 기본 시나리오 (각 VU가 반복 실행)export default function () { const res = http.get('https://api.example.com/products');
check(res, { 'status 200': (r) => r.status === 200, 'p95 < 300ms': (r) => r.timings.duration < 300, });
sleep(1); // 실제 사용자처럼 1초 대기}k6 run test.js3가지 시나리오 패턴
섹션 제목: “3가지 시나리오 패턴”Stress Test — 단계적 부하 증가
섹션 제목: “Stress Test — 단계적 부하 증가”export const options = { stages: [ { duration: '2m', target: 50 }, // 2분에 걸쳐 50 VU로 증가 { duration: '5m', target: 50 }, // 5분 유지 { duration: '2m', target: 100 }, // 100 VU로 증가 { duration: '5m', target: 100 }, // 5분 유지 { duration: '2m', target: 200 }, // 200 VU로 증가 { duration: '5m', target: 200 }, // 5분 유지 { duration: '2m', target: 0 }, // 종료 ], thresholds: { http_req_duration: ['p(95)<500'], http_req_failed: ['rate<0.01'], },};Spike Test — 급격한 트래픽 폭증
섹션 제목: “Spike Test — 급격한 트래픽 폭증”export const options = { stages: [ { duration: '1m', target: 10 }, // 정상 트래픽 { duration: '10s', target: 500 }, // 10초 내 500 VU 급증 { duration: '3m', target: 500 }, // 3분 유지 { duration: '10s', target: 10 }, // 빠른 복귀 { duration: '3m', target: 10 }, // 복구 시간 관찰 ],};Soak Test — 장시간 안정성 검증
섹션 제목: “Soak Test — 장시간 안정성 검증”export const options = { stages: [ { duration: '5m', target: 50 }, // 워밍업 { duration: '4h', target: 50 }, // 4시간 유지 (메모리 누수 탐지) { duration: '5m', target: 0 }, ], thresholds: { // Soak에서는 시간이 지나도 p95가 올라가면 안 됨 http_req_duration: ['p(95)<500', 'p(99)<1000'], },};실전 시나리오: 인증 + API 흐름
섹션 제목: “실전 시나리오: 인증 + API 흐름”import http from 'k6/http';import { check, group, sleep } from 'k6';import { Trend, Rate } from 'k6/metrics';
// 커스텀 지표const checkoutDuration = new Trend('checkout_duration');const paymentErrorRate = new Rate('payment_errors');
export const options = { scenarios: { // 일반 사용자: 상품 탐색 browse: { executor: 'constant-vus', vus: 100, duration: '5m', }, // 구매 사용자: 결제 완료 purchase: { executor: 'constant-vus', vus: 20, duration: '5m', }, },};
// 공통 변수const BASE_URL = 'https://api.example.com';
export default function () { group('로그인', () => { const loginRes = http.post(`${BASE_URL}/auth/login`, JSON.stringify({ email: 'test@example.com', password: 'password123', }), { headers: { 'Content-Type': 'application/json' }, });
check(loginRes, { '로그인 성공': (r) => r.status === 200 });
const token = loginRes.json('access_token');
group('상품 목록 조회', () => { const productsRes = http.get(`${BASE_URL}/products`, { headers: { Authorization: `Bearer ${token}` }, }); check(productsRes, { '상품 조회 성공': (r) => r.status === 200 }); });
group('결제', () => { const start = Date.now();
const checkoutRes = http.post(`${BASE_URL}/orders`, JSON.stringify({ product_id: 'prod-001', quantity: 1, }), { headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, });
checkoutDuration.add(Date.now() - start); paymentErrorRate.add(checkoutRes.status !== 201);
check(checkoutRes, { '주문 생성 성공': (r) => r.status === 201 }); }); });
sleep(Math.random() * 2 + 1); // 1~3초 랜덤 대기}임계치(Threshold) 설정
섹션 제목: “임계치(Threshold) 설정”export const options = { thresholds: { // 내장 지표 http_req_duration: [ 'p(50)<100', // 중앙값 100ms 'p(95)<300', // p95 300ms 'p(99)<1000', // p99 1초 ], http_req_failed: ['rate<0.01'], // 에러율 1%
// 특정 URL만 'http_req_duration{url:https://api.example.com/checkout}': ['p(95)<500'],
// 커스텀 지표 checkout_duration: ['p(95)<2000'], payment_errors: ['rate<0.001'], },};임계치 초과 시 k6는 exit code 99로 종료합니다. CI에서 배포 차단에 활용합니다.
결과 출력 & 시각화
섹션 제목: “결과 출력 & 시각화”# 기본 실행k6 run test.js
# Grafana + InfluxDB로 실시간 대시보드k6 run --out influxdb=http://localhost:8086/k6 test.js
# JSON으로 결과 저장k6 run --out json=results.json test.js
# CSV 출력k6 run --out csv=results.csv test.js# 주요 결과 지표 해석✓ checks.........................: 99.87%✗ http_req_failed...............: 0.13% ← 임계치 초과 시 ✗ http_req_duration.............: avg=145ms min=12ms med=98ms max=3.2s p(90)=289ms p(95)=412ms http_reqs......................: 45230 → 초당 251 TPS vus...........................: 50 → 최대 동시 사용자다음 단계
섹션 제목: “다음 단계”이 가이드를 내 서비스에 직접 적용해 보세요.
TestForge 무료 스캔 시작 →