🎯 k6 부하테스트 가이드
📑 목차
1. 설치
brew install k62. 기본 명령어
# 기본 실행
k6 run script.js
# VU(가상 유저) + 지속 시간 지정
k6 run --vus 10 --duration 30s script.js
# 결과를 JSON으로 저장
k6 run --out json=result.json script.js
# 상세 통계 출력
k6 run --summary-trend-stats="avg,p(90),p(95),p(99),max" script.js3. 스크립트 작성
💡 기본 구조
import http from 'k6/http';
import { check, sleep } from 'k6';
import { Trend, Rate } from 'k6/metrics';
// 커스텀 메트릭
const orderDuration = new Trend('order_duration');
const orderSuccess = new Rate('order_success');
// 부하 시나리오 설정
export const options = {
stages: [
{ duration: '10s', target: 10 }, // 워밍업
{ duration: '30s', target: 50 }, // 부하 증가
{ duration: '20s', target: 100 }, // 피크
{ duration: '10s', target: 0 }, // 쿨다운
],
thresholds: {
http_req_duration: ['p(95)<500'], // 95%ile 500ms 이하
order_success: ['rate>0.9'], // 성공률 90% 이상
},
};
// 각 VU가 반복 실행하는 함수
export default function () {
const res = http.get('https://example.com/api/items');
check(res, {
'status 200': r => r.status === 200,
'body ok': r => r.body.length > 0,
});
sleep(1);
}💡 타임딜 프로젝트 예시 (재고 경쟁 시뮬레이션)
import http from 'k6/http';
import { check, sleep } from 'k6';
import { Trend, Rate } from 'k6/metrics';
const BASE_URL = 'http://<NLB_URL>';
const orderDuration = new Trend('order_duration');
const orderSuccess = new Rate('order_success');
export const options = {
stages: [
{ duration: '10s', target: 10 },
{ duration: '30s', target: 50 },
{ duration: '20s', target: 100 },
{ duration: '10s', target: 0 },
],
thresholds: {
http_req_duration: ['p(95)<500'],
order_success: ['rate>0.9'],
},
};
export default function () {
// 1. 목록 조회
const listRes = http.get(`${BASE_URL}/api/timedeals`);
check(listRes, { 'list 200': r => r.status === 200 });
sleep(0.5);
// 2. 주문 (1~3번 딜 랜덤)
const payload = JSON.stringify({
timedealId: Math.ceil(Math.random() * 3),
quantity: 1,
});
const orderRes = http.post(`${BASE_URL}/api/orders`, payload, {
headers: { 'Content-Type': 'application/json' },
});
const ok = check(orderRes, {
'order 200': r => r.status === 200,
'order completed': r => {
try { return JSON.parse(r.body).status === 'COMPLETED'; }
catch { return false; }
},
});
orderDuration.add(orderRes.timings.duration);
orderSuccess.add(ok);
sleep(1);
}4. 실행 패턴
| 목적 | 명령어 |
|---|---|
| 기본 실행 | k6 run script.js |
| 스파이크 테스트 | k6 run --vus 200 --duration 10s script.js |
| 상세 통계 | k6 run --summary-trend-stats="avg,p(90),p(95),p(99),max" script.js |
| 결과 저장 | k6 run --out json=result.json script.js |
# 원라이너 (스크립트 파일 없이)
k6 run --vus 20 --duration 20s - <<'EOF'
import http from 'k6/http';
export default () => { http.get('https://example.com'); }
EOF5. 결과 해석
checks.........................: 94.20% ✓ 5652 ✗ 349
data_received..................: 1.2 MB 20 kB/s
http_req_duration..............: avg=142ms p(90)=310ms p(95)=450ms p(99)=820ms
http_req_failed................: 5.80% ✗ 349
order_success..................: 91.30% ✓ 2743 ✗ 261
vus............................: 100 min=10 max=100
| 항목 | 의미 | 기준 |
|---|---|---|
p(95) | 95%의 요청이 이 시간 이하 | < 500ms 권장 |
http_req_failed | 서버 에러(5xx) 비율 | < 1% 권장 |
order_success rate | 비즈니스 성공률 (재고 부족 포함) | 목표에 따라 다름 |
checks | check() 통과율 | > 99% 권장 |
thresholds 설정
thresholds에서 조건을 벗어나면 k6가 exit code 1로 종료됨 → CI/CD 파이프라인에서 게이트로 활용 가능
stages vs --vus/--duration
stages: 점진적 부하 증가/감소 시나리오 (스크립트에 정의)--vus --duration: 고정 부하 (CLI 플래그, 스크립트 stages 무시)