菜单
开源

性能测试

在上一节中,您创建了一个可工作的脚本来测试端点功能。下一步是测试该系统在负载下的响应情况。这需要设置一些 options 来配置与测试逻辑无关的测试部分。

在本教程中,您将学习如何

这些示例基于上一节中的脚本。

背景: 满足服务水平目标

为了评估登录端点的性能,您的团队可能已经定义了服务水平目标 (service level objectives) (SLOs)。例如

  • 99% 的请求应该成功
  • 99% 的请求延迟应该小于或等于 1000ms

服务必须在不同类型的正常流量下满足这些 SLO。

通过阈值断言性能

为了规范化 SLO,添加阈值 (thresholds) 来测试您的系统是否符合其目标标准。

阈值在options 对象中设置。

JavaScript
export const options = {
  // define thresholds
  thresholds: {
    http_req_failed: ['rate<0.01'], // http errors should be less than 1%
    http_req_duration: ['p(99)<1000'], // 99% of requests should be below 1s
  },
};

将包含阈值的 options 对象添加到您的脚本 api-test.js 中。

JavaScript
// import necessary modules
import { check } from 'k6';
import http from 'k6/http';

// define configuration
export const options = {
  // define thresholds
  thresholds: {
    http_req_failed: ['rate<0.01'], // http errors should be less than 1%
    http_req_duration: ['p(99)<1000'], // 99% of requests should be below 1s
  },
};

export default function () {
  // define URL and request body
  const url = 'https://quickpizza.grafana.com/api/users/token/login';
  const payload = JSON.stringify({
    username: 'default',
    password: '1234',
  });
  const params = {
    headers: {
      'Content-Type': 'application/json',
    },
  };

  // send a post request and save response as a variable
  const res = http.post(url, payload, params);

  // check that response is 200
  check(res, {
    'response code was 200': (res) => res.status == 200,
  });
}

运行测试。

bash
k6 run api-test.js

检查控制台输出,确定性能是否超过了阈值。

  █ THRESHOLDS

    http_req_duration
    ✓ 'p(99)<1000' p(99)=148.21ms

    http_req_failed
    ✗ 'rate<0.01' rate=20.%

✓ 和 ✗ 符号表示性能阈值是否通过或失败。

在不断增加的负载下测试性能

现在您的脚本包含了模拟用户行为的逻辑,以及对功能(检查 checks)和性能(阈值 thresholds)的断言。

现在是时候增加负载以查看其性能了。要增加负载,请使用 scenarios 属性。Scenarios 根据虚拟用户数 (VUs)、迭代次数、VUs 或迭代率来安排负载。

运行冒烟测试

从小开始。运行一个冒烟测试 (smoke test)(一个小型测试,用于确认脚本能正常工作),检查您的脚本是否可以处理最小负载。

要做到这一点,使用--iterations 标志,参数设置为 10 或更少。

bash
k6 run --iterations 10 api-test.js

如果服务无法接收 10 次迭代,则系统存在一些严重的性能问题需要调试。幸好您提早运行了测试!

运行中等负载测试

通常情况下,流量不会一次全部到达。相反,它会逐渐增加到峰值负载。为了模拟这一点,测试人员会分阶段 (stages) 增加负载。

将以下 scenario 属性添加到您的 options 对象中,然后重新运行测试。

JavaScript
export const options = {
  // define thresholds
  thresholds: {
    http_req_failed: ['rate<0.01'], // http errors should be less than 1%
    http_req_duration: ['p(99)<1000'], // 99% of requests should be below 1s
  },
  // define scenarios
  scenarios: {
    // arbitrary name of scenario
    average_load: {
      executor: 'ramping-vus',
      stages: [
        // ramp up to average load of 20 virtual users
        { duration: '10s', target: 20 },
        // maintain load
        { duration: '50s', target: 20 },
        // ramp down to zero
        { duration: '5s', target: 0 },
      ],
    },
  },
};

由于这是一个学习环境,这些阶段仍然很短。冒烟测试以迭代次数定义负载,而此配置使用ramping-vus 执行器 (executor) 通过虚拟用户数和持续时间来表达负载。

不带命令行标志运行测试

bash
k6 run api-test.js

负载较小,因此服务器应该在阈值范围内运行。但是,此测试服务器可能同时被许多 k6 学习者使用,因此结果可能不可预测。

注意

此时,最好有一个图形界面来可视化指标(metrics)随时间的推移。k6 有多种输出格式,可以作为许多可视化工具(包括开源和商业工具)的输入。有关想法,请阅读可视化 k6 结果的方法

渐增负载直到阈值失败

最后,运行一个断点测试 (breakpoint test),探测系统的极限。在这种情况下,运行测试直到可用性(错误率)阈值被超过。

为此

  1. abortOnFail 属性添加到 http_req_failed 中。
JavaScript
export const options = {
  // define thresholds
  thresholds: {
    http_req_failed: [{ threshold: 'rate<0.01', abortOnFail: true }], // http errors should be less than 1%, otherwise abort the test
    http_req_duration: ['p(99)<1000'], // 99% of requests should be below 1s
  },
  // ...
};
  1. 更新 scenarios 属性,使测试渐增负载直到失败。
JavaScript
export const options = {
  thresholds: {
    http_req_failed: [{ threshold: 'rate<0.01', abortOnFail: true }],
    http_req_duration: ['p(99)<1000'],
  },
  scenarios: {
    // define scenarios
    breaking: {
      executor: 'ramping-vus',
      stages: [
        { duration: '10s', target: 20 },
        { duration: '50s', target: 20 },
        { duration: '50s', target: 40 },
        { duration: '50s', target: 60 },
        { duration: '50s', target: 80 },
        { duration: '50s', target: 100 },
        { duration: '50s', target: 120 },
        { duration: '50s', target: 140 },
        //....
      ],
    },
  },
};

以下是完整脚本。

JavaScript
// import necessary modules
import { check } from 'k6';
import http from 'k6/http';

// define configuration
export const options = {
  // define thresholds
  thresholds: {
    http_req_failed: [{ threshold: 'rate<0.01', abortOnFail: true }], // availability threshold for error rate
    http_req_duration: ['p(99)<1000'], // Latency threshold for percentile
  },
  // define scenarios
  scenarios: {
    breaking: {
      executor: 'ramping-vus',
      stages: [
        { duration: '10s', target: 20 },
        { duration: '50s', target: 20 },
        { duration: '50s', target: 40 },
        { duration: '50s', target: 60 },
        { duration: '50s', target: 80 },
        { duration: '50s', target: 100 },
        { duration: '50s', target: 120 },
        { duration: '50s', target: 140 },
        //....
      ],
    },
  },
};

export default function () {
  // define URL and request body
  const url = 'https://quickpizza.grafana.com/api/users/token/login';
  const payload = JSON.stringify({
    username: 'default',
    password: '1234',
  });
  const params = {
    headers: {
      'Content-Type': 'application/json',
    },
  };

  // send a post request and save response as a variable
  const res = http.post(url, payload, params);

  // check that response is 200
  check(res, {
    'response code was 200': (res) => res.status == 200,
  });
}

运行测试。

bash
k6 run api-test.js

阈值失败了吗?如果还没有,增加一个更高目标(target)的阶段,然后重试。重复此步骤,直到阈值终止测试。

bash
ERRO[0010] thresholds on metrics 'http_req_duration, http_req_failed' were breached; at least one has abortOnFail enabled, stopping test prematurely

下一步

在本教程中,您使用了阈值 (thresholds) 来断言性能,并使用场景 (Scenarios) 来安排不同的负载模式。要了解更多关于常用负载模式及其目标的信息,请阅读负载测试类型

本教程的下一步将展示如何解释测试结果。这包括过滤结果和添加自定义指标。