0환경 설정
1
k6 설치 (Linux/Mac) —
brew install k6 또는 sudo apt install k62
k6 설치 (Windows) —
winget install k6 --source winget 또는 공식 MSI 설치 파일 사용3
버전 확인 —
k6 version → k6 v0.50+ 확인4
테스트 대상 서버 — 로컬 서버 또는
https://test-api.k6.io 공개 테스트 API 활용 가능1Load 시나리오 — Ramp-up/Down
실제 트래픽 패턴을 재현하는 stages 기반 Load 테스트입니다. 점진적으로 부하를 높였다가 낮추는 표준 패턴으로, 서버의 임계점과 회복력을 함께 검증합니다.
load_test.js — Ramp-up / Steady / Ramp-down
100 VU까지 점진적으로 올린 뒤 5분 유지, 다시 0으로 내리는 표준 Load 시나리오.
jsimport http from 'k6/http';
import { sleep, check } from 'k6';
export const options = {
stages: [
{ duration: '2m', target: 50 }, // Ramp-up: 0 → 50 VU
{ duration: '5m', target: 100 }, // Ramp-up: 50 → 100 VU
{ duration: '5m', target: 100 }, // Steady state: 100 VU 유지
{ duration: '2m', target: 0 }, // Ramp-down: 100 → 0 VU
],
};
const BASE_URL = 'https://test-api.k6.io';
export default function () {
const res = http.get(`${BASE_URL}/public/crocodiles/`);
check(res, {
'status is 200': (r) => r.status === 200,
'response time < 500ms': (r) => r.timings.duration < 500,
});
sleep(1);
}
실행:
k6 run load_test.js — 터미널에서 실시간 메트릭을 확인할 수 있습니다. Grafana로 시각화하려면 k6 run --out influxdb=http://localhost:8086/k6 load_test.js를 사용하세요.Stress / Spike 시나리오
stress_spike.js — 한계점 탐색 및 Spike 테스트
서버 한계를 찾는 Stress와 갑작스런 트래픽 급증을 시뮬레이션하는 Spike를 하나의 파일에서 선택 실행.
jsimport http from 'k6/http';
import { sleep, check } from 'k6';
// STRESS: 한계점까지 점진 증가
export const stressOptions = {
stages: [
{ duration: '2m', target: 100 },
{ duration: '5m', target: 200 },
{ duration: '5m', target: 300 },
{ duration: '2m', target: 0 },
],
};
// SPIKE: 갑작스러운 트래픽 급증
export const spikeOptions = {
stages: [
{ duration: '30s', target: 10 },
{ duration: '10s', target: 500 }, // 순간 급증
{ duration: '1m', target: 500 },
{ duration: '10s', target: 10 }, // 회복 후 정상
{ duration: '30s', target: 0 },
],
};
// 실행 시: K6_SCENARIO=spike k6 run stress_spike.js
const scenario = __ENV.K6_SCENARIO || 'stress';
export const options = scenario === 'spike' ? spikeOptions : stressOptions;
export default function () {
const res = http.get('https://test-api.k6.io/public/crocodiles/');
check(res, { 'status 200': (r) => r.status === 200 });
sleep(1);
}
2API 인증 흐름 — 로그인 → JWT → API 호출
실제 서비스 대부분은 인증이 필요합니다. 로그인으로 토큰을 발급받아 이후 요청에 Bearer 헤더를 붙이는 실무 패턴입니다.
auth_flow.js — 로그인 → 토큰 발급 → 인증 API 호출
setup() 함수에서 토큰을 한 번만 발급하고, VU들이 공유해서 사용하는 효율적인 패턴.
jsimport http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 50,
duration: '3m',
};
const BASE_URL = 'https://test-api.k6.io';
// setup: 부하 시작 전 1회 실행 → 토큰 발급
export function setup() {
const loginRes = http.post(
`${BASE_URL}/auth/token/login/`,
JSON.stringify({ username: 'test_case', password: '1234' }),
{ headers: { 'Content-Type': 'application/json' } }
);
check(loginRes, { 'login OK': (r) => r.status === 200 });
const token = loginRes.json('access');
return { token };
}
// 메인 VU 함수 — data는 setup()의 반환값
export default function (data) {
const params = {
headers: {
Authorization: `Bearer ${data.token}`,
'Content-Type': 'application/json',
},
};
// 1. 목록 조회
const listRes = http.get(`${BASE_URL}/my/crocodiles/`, params);
check(listRes, {
'list status 200': (r) => r.status === 200,
'list has items': (r) => r.json().length > 0,
});
sleep(0.5);
// 2. 새 항목 생성
const createRes = http.post(
`${BASE_URL}/my/crocodiles/`,
JSON.stringify({ name: `croc_${__VU}_${__ITER}`, sex: 'M', date_of_birth: '2020-01-01' }),
params
);
check(createRes, { 'create status 201': (r) => r.status === 201 });
sleep(1);
}
3Thresholds & Checks — 성능 기준 설정
Thresholds는 테스트의 합격/불합격 기준입니다. CI/CD에서 기준 미달 시 자동으로 빌드를 실패시킬 수 있습니다.
thresholds.js — SLA 기반 성능 기준 정의
p95 응답시간 500ms 이하, 에러율 1% 미만, Check 통과율 99% 이상을 기준으로 설정.
jsimport http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 30,
duration: '5m',
thresholds: {
// HTTP 응답 시간 기준
http_req_duration: [
'p(95)<500', // 95%ile이 500ms 미만
'p(99)<1000', // 99%ile이 1000ms 미만
],
// HTTP 에러율
http_req_failed: ['rate<0.01'], // 에러율 1% 미만
// Check 성공률 (커스텀 기준 이름)
'checks{type:api}': ['rate>0.99'],
// 특정 엔드포인트만 별도 기준
'http_req_duration{endpoint:list}': ['p(95)<300'],
},
};
export default function () {
// 태그로 엔드포인트 구분
const listRes = http.get('https://test-api.k6.io/public/crocodiles/', {
tags: { endpoint: 'list' },
});
check(listRes, {
'status 200': (r) => r.status === 200,
'body not empty': (r) => r.body.length > 0,
}, { type: 'api' });
sleep(1);
}
Threshold 실패 시 k6는 exit code 99를 반환합니다. GitHub Actions에서
if: failure()로 실패 알림을 설정하거나, Slack 알림을 연동할 수 있습니다.4커스텀 메트릭 — 비즈니스 지표 수집
k6 내장 메트릭 외에도 비즈니스에 의미 있는 지표(결제 성공률, 장바구니 응답시간 등)를 직접 정의해서 수집할 수 있습니다.
custom_metrics.js — Trend·Counter·Rate·Gauge 예제
4가지 메트릭 타입을 모두 활용한 예제. InfluxDB + Grafana로 시각화 가능.
jsimport http from 'k6/http';
import { check, sleep } from 'k6';
import { Trend, Counter, Rate, Gauge } from 'k6/metrics';
// 커스텀 메트릭 정의
const checkoutDuration = new Trend('checkout_duration_ms'); // 시간 분포
const errorCount = new Counter('error_count'); // 누적 카운트
const checkoutSuccess = new Rate('checkout_success_rate'); // 성공률
const activeUsers = new Gauge('active_user_count'); // 현재값
export const options = {
vus: 20,
duration: '3m',
thresholds: {
checkout_duration_ms: ['p(95)<800'],
checkout_success_rate: ['rate>0.95'],
},
};
export default function () {
activeUsers.add(__VU); // 현재 VU 수 기록
const start = Date.now();
const res = http.post(
'https://test-api.k6.io/my/crocodiles/',
JSON.stringify({ name: 'checkout_test', sex: 'M', date_of_birth: '2020-01-01' }),
{ headers: { 'Content-Type': 'application/json' } }
);
const duration = Date.now() - start;
checkoutDuration.add(duration); // ms 기록
const ok = check(res, { 'checkout ok': (r) => r.status === 201 });
checkoutSuccess.add(ok);
if (!ok) errorCount.add(1);
sleep(1);
}
5GitHub Actions CI/CD 자동화
PR 머지 또는 배포 이후 자동으로 성능 테스트를 실행하고, Threshold 실패 시 워크플로우를 중단시키는 실무 패턴입니다.
.github/workflows/k6-perf.yml — 성능 테스트 자동화
PR이 main에 머지될 때마다 k6 성능 테스트를 실행하고 결과를 PR 코멘트로 남기는 워크플로우.
yamlname: k6 Performance Test
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
k6-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install k6
run: |
curl https://github.com/grafana/k6/releases/download/v0.50.0/k6-v0.50.0-linux-amd64.tar.gz -L | tar xvz --strip-components 1
- name: Run Load Test
env:
BASE_URL: ${{ secrets.STAGING_URL }}
run: |
./k6 run \
--out json=results.json \
--env BASE_URL=$BASE_URL \
tests/load_test.js
- name: Upload Results
if: always()
uses: actions/upload-artifact@v4
with:
name: k6-results
path: results.json
- name: Comment PR with Results
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const results = JSON.parse(fs.readFileSync('results.json', 'utf8'));
// 마지막 summary 찾기
const summary = results.filter(r => r.type === 'Point' && r.metric === 'http_req_duration');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `### k6 성능 테스트 결과\n${JSON.stringify(summary.slice(-5), null, 2)}`
});
k6 Cloud 연동:
k6 cloud run load_test.js로 분산 부하를 클라우드에서 실행할 수 있습니다. 무료 플랜으로 월 50회 테스트 실행이 가능합니다. k6 완전 가이드에서 Cloud 설정 방법을 확인하세요.