阈值
阈值是您为测试指标定义的通过/失败标准。如果被测系统 (SUT) 的性能未达到您定义的阈值条件,**测试将以失败状态结束。**
通常,测试人员使用阈值来规范化他们的 SLO。例如,您可以针对以下任何组合的期望创建阈值
- 请求的错误率低于 1%。
- 95% 的请求响应时间低于 200 毫秒。
- 99% 的请求响应时间低于 400 毫秒。
- 特定端点始终在 300 毫秒内响应。
- 自定义指标 的任何条件。
阈值对于 负载测试自动化 也至关重要
- 为您的测试设置阈值。
- 自动化您的执行
- 为测试失败设置告警。
之后,您只需要在被测系统 (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 () {
http.get('https://quickpizza.grafana.com');
}
换句话说,当您定义阈值时,请指定一个用于 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
{ expected_response:true }..: avg=151.06ms min=151.06ms med=151.06ms max=151.06ms p(90)=151.06ms p(95)=151.06ms
http_req_failed................: 0.00% ✓ 0 ✗ 1
在本例中,测试满足了两个阈值的标准。k6 将此测试视为 pass
,并以退出码 0
退出。
如果任何阈值失败,阈值名称(http_req_failed
, http_req_duration
)旁边的小绿勾 ✓ 将变成红叉 ✗,并且 k6 将以非零退出码退出。
阈值语法
要使用阈值,请按照以下步骤操作
在
options
对象的thresholds
属性中,使用您希望设置阈值的指标名称设置一个键export const options = { thresholds: { /* ... */ }, };
定义至少一个阈值表达式。您可以通过两种方式进行
- 短格式将所有阈值表达式作为字符串放在一个数组中。
- 长格式将每个阈值放在一个对象中,并带有一些额外属性用于 在失败时中止 测试。
export const options = { thresholds: { //short format METRIC_NAME1: ['THRESHOLD_EXPRESSION', `...`], //long format METRIC_NAME2: [ { threshold: 'THRESHOLD_EXPRESSION', abortOnFail: true, // boolean delayAbortEval: '10s', // string }, ], // full format }, };
请注意,
METRIC_NAME1
和THRESHOLD_EXPRESSION
是占位符。实际文本必须是指标名称和阈值表达式。
此声明为指标 metric_name1
和 metric_name2
配置阈值。为了确定阈值是通过还是失败,脚本会评估 'threshold_expression'
。
阈值表达式语法
阈值表达式评估结果为 true
或 false
。阈值表达式必须采用以下格式
<aggregation_method> <operator> <value>
以下是一些阈值表达式的示例
avg < 200
// 平均时长必须小于 200 毫秒count >= 500
// 计数必须大于或等于 500p(90) < 300
// 90% 的样本必须低于 300
按类型划分的聚合方法
k6 根据 其类型 聚合指标。这些聚合方法构成了阈值表达式的一部分。
指标类型 | 聚合方法 |
---|---|
Counter | count 和 rate |
Gauge | 值 |
Rate | 速率 |
Trend | avg , min , max , med 和 p(N) ,其中 N 指定阈值百分位数的值,表示为 0.0 到 100 之间的数字。例如,p(99.99) 表示 99.99th 百分位数。值以毫秒为单位。 |
此(略显刻意)示例脚本使用了所有不同类型的指标,并为每个指标设置了不同类型的阈值
import http from 'k6/http';
import { Trend, Rate, Counter, Gauge } from 'k6/metrics';
import { sleep } from 'k6';
export const TrendRTT = new Trend('RTT');
export const RateContentOK = new Rate('ContentOK');
export const GaugeContentSize = new Gauge('ContentSize');
export const CounterErrors = new Counter('Errors');
export const options = {
thresholds: {
// Count: Incorrect content cannot be returned more than 99 times.
Errors: ['count<100'],
// Gauge: returned content must be smaller than 4000 bytes
ContentSize: ['value<4000'],
// Rate: content must be OK more than 95 times
ContentOK: ['rate>0.95'],
// Trend: Percentiles, averages, medians, and minimums
// must be within specified milliseconds.
RTT: ['p(99)<300', 'p(70)<250', 'avg<200', 'med<150', 'min<100'],
},
};
export default function () {
const res = http.get('https://quickpizza.grafana.com/api/json?name=Bert');
const contentOK = res.json('name') === 'Bert';
TrendRTT.add(res.timings.duration);
RateContentOK.add(contentOK);
GaugeContentSize.add(res.body.length);
CounterErrors.add(!contentOK);
sleep(1);
}
注意
不要通过重复相同的对象键为同一指标指定多个阈值。
由于阈值被定义为 JavaScript 对象的属性,您无法使用相同的属性名称指定多个阈值。
export const options = {
thresholds: {
// don't use the same metric more than once here
metric_name: ['count<100'],
metric_name: ['rate<50'],
},
};
其余的将被 **静默** 忽略。如果您想为一个指标设置多个阈值,请使用 一个针对同一键的数组 来指定它们。
可复制粘贴的阈值示例
开始使用阈值最快的方法是使用 内置指标。这里有一些您可以立即使用的复制粘贴示例。
有关更具体的阈值示例,请参阅 Counter、Gauge、Trend 和 Rate 页面。
一定百分比的请求在指定时长内完成
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');
sleep(1);
}
错误率低于 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');
sleep(1);
}
单个指标上的多个阈值
您也可以为一个指标应用多个阈值。此阈值对不同请求百分位数有不同的时长要求。
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 () {
const res1 = http.get('https://quickpizza.grafana.com');
sleep(1);
}
组时长的阈值
您可以为 每个组 设置阈值。此代码包含针对单个请求和批量请求的组。每个组都有不同的阈值。
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([
['GET', 'https://quickpizza.grafana.com/api/json?letter=a'],
['GET', 'https://quickpizza.grafana.com/api/json?letter=b'],
['GET', 'https://quickpizza.grafana.com/api/json?letter=c'],
]);
});
sleep(1);
}
为特定标签设置阈值
为单个 URL 或特定标签指定阈值通常很有用。在 k6 中,带标签的请求会创建可在阈值中使用的子指标
export const options = {
thresholds: {
'metric_name{tag_name:tag_value}': ['threshold_expression'],
},
};
这里有一个完整的示例。
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
'http_req_duration{type:staticContent}': ['p(95)<200'], // threshold on static content only
},
};
export default function () {
const res1 = http.get('https://quickpizza.grafana.com/api/headers', {
tags: { type: 'API' },
});
const res2 = http.get('https://quickpizza.grafana.com/api/json', {
tags: { type: 'API' },
});
const responses = http.batch([
[
'GET',
'https://quickpizza.grafana.com/favicon.ico',
null,
{ tags: { type: 'staticContent' } },
],
['GET', 'https://quickpizza.grafana.com/admin', null, { tags: { type: 'staticContent' } }],
]);
sleep(1);
}
当阈值被触发时中止测试
如果您想在阈值被触发时立即中止测试,请将 abortOnFail
属性设置为 true
。当您设置 abortOnFail
时,测试运行会在 *阈值失败时立即停止*。
然而,有时测试可能会提前触发阈值并中止,而测试尚未生成重要数据。为了防止这些情况,您可以使用 delayAbortEval
来延迟 abortOnFail
。在此脚本中,abortOnFail
被延迟了十秒。十秒后,如果测试未能通过 p(99) < 10
阈值,它将中止。
export const options = {
thresholds: {
metric_name: [
{
threshold: 'p(99) < 10', // string
abortOnFail: true, // boolean
delayAbortEval: '10s', // string
/*...*/
},
],
},
};
字段如下
名称 | 类型 | 描述 |
---|---|---|
threshold | string | 这是指定要评估的阈值条件的阈值表达式字符串。 |
abortOnFail | boolean | 如果在测试完成前阈值评估为 false,是否中止测试。 |
delayAbortEval | string | 如果您想延迟阈值评估以收集一些指标样本,您可以使用相对时间字符串(如 10s 、1m 等)指定延迟的时间量。 |
这里是一个示例
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 的退出状态。
如果您仅使用 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);
}
在此示例中,threshold
配置在 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);
}