기본 명령어
- k6 run script.js
- k6 run --vus 10 --duration 30s script.js
- VU/시간으로 간단 부하
- 10명이 30초 동안 계속 요청
- k6 run --stage 10s:10 --stage 30s:50 --stage 10s:0 script.js
- 단계로 램프업/유지/램프다운
- 10초 동안 10VU까지 증가, 30초 동안 50VU 유지, 10초 동안 0VU으로 감소
- BASE_URL="http://localhost:8080" TOKEN="abc" k6 run script.js
스크립트에선 이런 방식으로 받음
const BASE_URL = __ENV.BASE_URL;
const TOKEN = __ENV.TOKEN;
- k6 run --summary-export=summary.json script.js
- docker run --rm -i grafana/k6 run - < script.js
스크립트
import http from "k6/http"
- HTTP요청 http.get/post/put/del
export default function () {
http.get("http://localhost:8080/health");
http.post("http://localhost:8080/login", JSON.stringify({ id: "a", pw: "b" }), {
headers: { "Content-Type": "application/json" },
});
// 여러 요청을 병렬로
http.batch([
["GET", "http://localhost:8080/a"],
["GET", "http://localhost:8080/b"],
]);
}
import { check } from "k6";
- 검증
export default function () {
const res = http.get("http://localhost:8080/health");
check(res, {
"status is 200": (r) => r.status === 200,
"body has ok": (r) => r.body.includes("ok"),
});
}
import { sleep } from "k6";
- 대기
export default function () {
sleep(1);
}
import { group } from "k6";
- 구간 묶기
export default function () {
group("login", () => {
const res = http.post("http://localhost:8080/login", JSON.stringify({ id: "a", pw: "b" }), {
headers: { "Content-Type": "application/json" },
});
check(res, { "login 200": (r) => r.status === 200 });
});
group("buy ticket", () => {
const res = http.post("http://localhost:8080/ticket/buy", null);
check(res, { "buy ok": (r) => r.status === 200 || r.status === 201 });
});
}
thresholds
-성능 합격/불합격 기준
export const options = {
thresholds: {
http_req_failed: ["rate<0.01"], // 실패율 1% 미만
http_req_duration: ["p(95)<500"], // p95 500ms 미만
},
};
메트릭 직접 만들기
import { Counter, Rate, Trend } from "k6/metrics";
import http from "k6/http";
const success = new Counter("success_count");
const failRate = new Rate("fail_rate");
const latency = new Trend("api_latency_ms");
export default function () {
const res = http.get("http://localhost:8080/health");
latency.add(res.timings.duration);
const ok = res.status === 200;
failRate.add(!ok);
if (ok) success.add(1);
}
시나리오(executors): 도착률 기반(초당 N회) 같은 오픈 모델
export const options = {
scenarios: {
open_model: {
executor: "constant-arrival-rate",
rate: 200, // 초당 200 iteration
timeUnit: "1s",
duration: "30s",
preAllocatedVUs: 50, // 미리 확보할 VU
maxVUs: 200,
},
},
};
setup() / teardown() (테스트 전/후 1번만)
import http from "k6/http";
export function setup() {
// 예: 로그인해서 토큰 1번만 받아서 공유
const res = http.post("http://localhost:8080/login", JSON.stringify({ id: "a", pw: "b" }), {
headers: { "Content-Type": "application/json" },
});
return { token: res.json("token") };
}
export default function (data) {
http.get("http://localhost:8080/me", {
headers: { Authorization: `Bearer ${data.token}` },
});
}
export function teardown(data) {
// 예: 테스트 후 정리 요청
}
일반 부하(램프업 → 유지)
import http from "k6/http";
import { check, sleep } from "k6";
const BASE_URL = __ENV.BASE_URL || "http://localhost:8080";
export const options = {
stages: [
{ duration: "30s", target: 50 },
{ duration: "1m", target: 50 },
{ duration: "10s", target: 0 },
],
thresholds: {
http_req_failed: ["rate<0.01"],
http_req_duration: ["p(95)<800"],
},
};
export default function () {
const res = http.get(`${BASE_URL}/ticket/list`);
check(res, { "200": (r) => r.status === 200 });
sleep(0.3);
}