菜单
开源

阈值

阈值是您为测试指标定义的通过/失败标准。如果被测系统 (SUT) 的性能未达到您定义的阈值条件,**测试将以失败状态结束。**

通常,测试人员使用阈值来规范化他们的 SLO。例如,您可以针对以下任何组合的期望创建阈值

  • 请求的错误率低于 1%。
  • 95% 的请求响应时间低于 200 毫秒。
  • 99% 的请求响应时间低于 400 毫秒。
  • 特定端点始终在 300 毫秒内响应。
  • 自定义指标 的任何条件。

阈值对于 负载测试自动化 也至关重要

  1. 为您的测试设置阈值。
  2. 自动化您的执行
  3. 为测试失败设置告警。

之后,您只需要在被测系统 (SUT) 未达到其性能预期时关注测试即可。

HTTP 错误和响应时长的阈值示例

此示例脚本指定了两个阈值。一个阈值评估 HTTP 错误的速率 (http_req_failed 指标)。另一个阈值评估 95% 的响应是否在特定时长内完成 (http_req_duration 指标)。

bash
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 会输出类似于以下内容

bash
  █ 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 将以非零退出码退出。

阈值语法

要使用阈值,请按照以下步骤操作

  1. options 对象的 thresholds 属性中,使用您希望设置阈值的指标名称设置一个键

    bash
    export const options = {
      thresholds: {
        /* ... */
      },
    };
  2. 定义至少一个阈值表达式。您可以通过两种方式进行

    • 短格式将所有阈值表达式作为字符串放在一个数组中。
    • 长格式将每个阈值放在一个对象中,并带有一些额外属性用于 在失败时中止 测试。
    bash
    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_NAME1THRESHOLD_EXPRESSION 是占位符。实际文本必须是指标名称和阈值表达式。

此声明为指标 metric_name1metric_name2 配置阈值。为了确定阈值是通过还是失败,脚本会评估 'threshold_expression'

阈值表达式语法

阈值表达式评估结果为 truefalse。阈值表达式必须采用以下格式

<aggregation_method> <operator> <value>

以下是一些阈值表达式的示例

  • avg < 200 // 平均时长必须小于 200 毫秒
  • count >= 500 // 计数必须大于或等于 500
  • p(90) < 300 // 90% 的样本必须低于 300

按类型划分的聚合方法

k6 根据 其类型 聚合指标。这些聚合方法构成了阈值表达式的一部分。

指标类型聚合方法
Countercountrate
Gauge
Rate速率
Trendavg, min, max, medp(N),其中 N 指定阈值百分位数的值,表示为 0.0 到 100 之间的数字。例如,p(99.99) 表示 99.99th 百分位数。值以毫秒为单位。

此(略显刻意)示例脚本使用了所有不同类型的指标,并为每个指标设置了不同类型的阈值

bash
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 对象的属性,您无法使用相同的属性名称指定多个阈值。

bash
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 页面。

一定百分比的请求在指定时长内完成

bash
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%

bash
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);
}

单个指标上的多个阈值

您也可以为一个指标应用多个阈值。此阈值对不同请求百分位数有不同的时长要求。

bash
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);
}

组时长的阈值

您可以为 每个组 设置阈值。此代码包含针对单个请求和批量请求的组。每个组都有不同的阈值。

bash
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 中,带标签的请求会创建可在阈值中使用的子指标

bash
export const options = {
  thresholds: {
    'metric_name{tag_name:tag_value}': ['threshold_expression'],
  },
};

这里有一个完整的示例。

bash
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 阈值,它将中止。

bash
export const options = {
  thresholds: {
    metric_name: [
      {
        threshold: 'p(99) < 10', // string
        abortOnFail: true, // boolean
        delayAbortEval: '10s', // string
        /*...*/
      },
    ],
  },
};

字段如下

名称类型描述
thresholdstring这是指定要评估的阈值条件的阈值表达式字符串。
abortOnFailboolean如果在测试完成前阈值评估为 false,是否中止测试。
delayAbortEvalstring如果您想延迟阈值评估以收集一些指标样本,您可以使用相对时间字符串(如 10s1m 等)指定延迟的时间量。

这里是一个示例

bash
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 结果使整个测试运行失败。

结合使用 checksthresholds 通常很有用,可以充分利用两者的优点

bash
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。例如

bash
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);
}