임계값
k6 임계값(Thresholds) — 테스트의 합격·불합격 기준
부하 테스트가 끝나면 "그래서 통과했나요?"라는 질문이 나오기 마련이에요. k6의 임계값(thresholds) 은 이 질문에 답을 주는 메커니즘입니다. 테스트 메트릭에 대한 합격·불합격 기준을 정의하고, 그 조건을 충족하지 못하면 테스트를 실패 상태로 끝내요. 이번 글에서는 임계값의 기본 문법부터 오류율·응답 시간 기준, 특정 태그에 대한 임계값, 실패 시 즉시 중단하는 방법까지 정리해 볼게요.
출처: k6 공식 문서 — Thresholds 원본 URL: https://grafana.com/docs/k6/latest/using-k6/thresholds/
임계값이란 무엇인가
임계값은 테스트 메트릭에 대해 정의하는 합격·불합격 기준이에요. 테스트 대상 시스템(SUT)의 성능이 임계값 조건을 충족하지 못하면 테스트는 실패 상태로 끝납니다. 예를 들면 이런 기준이 임계값이 돼요.
- 요청 중 1% 미만이 오류를 반환한다.
- 95%의 요청이 200ms 미만으로 응답한다.
- 99%의 요청이 400ms 미만으로 응답한다.
- 특정 엔드포인트가 항상 300ms 안에 응답한다.
- 커스텀 메트릭의 어떤 조건.
임계값은 부하 테스트 자동화에도 필수적이에요.
- 테스트에 임계값을 준다.
- 실행을 자동화한다.
- 테스트 실패에 대한 알림을 설정한다.
그러면 SUT가 성능 기대치를 밑돌 때만 테스트를 신경 쓰면 됩니다.
HTTP 오류와 응답 시간 임계값 예제
이 샘플 스크립트는 임계값을 두 개 지정해요. 하나는 HTTP 오류율(http_req_failed 메트릭), 다른 하나는 95% 응답이 특정 시간 안에 끝나는지(http_req_duration 메트릭)를 평가합니다.
import http from 'k6/http';
export const options = {
thresholds: {
http_req_failed: ['rate<0.01'], // http errors should be less than 1%
http_req_duration: ['p(95)<200'], // 95% of requests should be below 200ms
},
};
export default function () {
즉, 임계값을 정의할 때는 pass 기준을 위한 표현식을 지정해요. 그 표현식이 테스트 종료 시 false로 평가되면, k6는 테스트 전체를 fail로 간주합니다. 이 스크립트를 실행하면 k6는 대략 아래처럼 출력해요.
█ THRESHOLDS
http_req_duration
✓ 'p(95)<200' p(95)=148.21ms
http_req_failed
✓ 'rate<0.01' rate=0.05%
█ TOTAL RESULTS
HTTP
http_req_duration..............: avg=151.06ms min=151.06ms med=151.06ms max=151.06ms p(90)=151.06ms p(95)=151.06ms
이 경우 테스트가 두 임계값 조건을 모두 충족했어요. k6는 이 테스트를 pass로 보고 종료 코드 0으로 끝납니다.
복사해서 쓰기 좋은 임계값 예제
지정한 시간 안에 끝나는 요청의 백분위
import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
thresholds: {
// 90% of requests must finish within 400ms.
http_req_duration: ['p(90) < 400'],
},
};
export default function () {
http.get('https://quickpizza.grafana.com');
오류율이 1% 미만
import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
thresholds: {
// During the whole test execution, the error rate must be lower than 1%.
http_req_failed: ['rate<0.01'],
},
};
export default function () {
http.get('https://quickpizza.grafana.com');
하나의 메트릭에 여러 임계값
import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
thresholds: {
// 90% of requests must finish within 400ms, 95% within 800, and 99.9% within 2s.
http_req_duration: ['p(90) < 400', 'p(95) < 800', 'p(99.9) < 2000'],
},
};
export default function () {
그룹 duration 임계값
group()을 쓰면 그룹별로도 임계값을 걸 수 있어요.
import http from 'k6/http';
import { group, sleep } from 'k6';
export const options = {
thresholds: {
'group_duration{group:::individualRequests}': ['avg < 400'],
'group_duration{group:::batchRequests}': ['avg < 200'],
},
vus: 1,
duration: '10s',
};
export default function () {
group('individualRequests', function () {
http.get('https://quickpizza.grafana.com/api/json?letter=a');
http.get('https://quickpizza.grafana.com/api/json?letter=b');
http.get('https://quickpizza.grafana.com/api/json?letter=c');
});
group('batchRequests', function () {
http.batch([
특정 태그에 대한 임계값
태그를 걸어 특정 요청에 대해서만 임계값을 평가할 수도 있어요.
import http from 'k6/http';
import { sleep } from 'k6';
import { Rate } from 'k6/metrics';
export const options = {
thresholds: {
'http_req_duration{type:API}': ['p(95)<500'], // threshold on API requests only
임계값 위반 시 테스트 즉시 중단
임계값을 위반하자마자 테스트를 중단하고 싶다면 abortOnFail 속성을 true로 설정해요. abortOnFail을 설정하면 테스트 실행이 임계값이 실패하는 즉시 멈춥니다. 그런데 때로는 테스트가 충분한 데이터를 만들기 전에 일찍 임계값을 실패해서 중단될 수 있어요. 이런 경우를 막으려면 delayAbortEval로 abortOnFail을 지연시킬 수 있습니다. 아래 스크립트는 abortOnFail을 10초 지연한 예시예요. 10초가 지난 후에도 p(99) < 10 임계값을 실패하면 테스트가 중단됩니다.
export const options = {
thresholds: {
metric_name: [
{
threshold: 'p(99) < 10', // string
abortOnFail: true, // boolean
delayAbortEval: '10s', // string
/*...*/
},
],
},
};
import http from 'k6/http';
export const options = {
vus: 30,
duration: '2m',
thresholds: {
http_req_duration: [{ threshold: 'p(99) < 10', abortOnFail: true }],
},
};
export default function () {
http.get('https://quickpizza.grafana.com');
}
주의 k6가 클라우드에서 실행될 때는 임계값이 60초마다 평가됩니다. 그래서
abortOnFail기능이 최대 60초까지 지연될 수 있어요.
체크로 부하 테스트 실패시키기
체크는 어서션을 코드화하기 좋지만, thresholds와 달리 checks는 k6의 종료 상태(exit status)에 영향을 주지 않아요. checks만으로 검증하면 check 결과로 전체 테스트 실행을 실패시킬 수 없습니다. checks와 thresholds를 조합하면 양쪽의 장점을 모두 얻을 수 있어요.
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 50,
duration: '10s',
thresholds: {
// the rate of successful checks should be higher than 90%
checks: ['rate>0.9'],
},
};
export default function () {
const res = http.get('https://quickpizza.grafana.com/api/status/500');
check(res, {
'status is 500': (r) => r.status == 500,
});
sleep(1);
}
이 예제에서는 checks 메트릭에 임계값을 걸어, 성공한 체크의 비율이 90%보다 높아야 한다고 정의했어요. 특정 체크나 체크 그룹에 기반한 임계값을 정의하려면 체크에 tags를 쓸 수도 있어요.
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 50,
duration: '10s',
thresholds: {
'checks{myTag:hola}': ['rate>0.9'],
},
};
export default function () {
let res;
res = http.get('https://quickpizza.grafana.com/api/status/500');
check(res, {
'status is 500': (r) => r.status == 500,
});
res = http.get('https://quickpizza.grafana.com/api/status/200');
check(
res,
{
'status is 200': (r) => r.status == 200,
},
{ myTag: 'hola' }
);
sleep(1);
}
더 알아보기
- 공식: k6 — Thresholds
- 공식: k6 — Checks