文章

K6工具

安装

Win 11 操作系统内置了 winget 安装工具,所以笔者直接使用 winget 安装 k6:

1
winget install k6

image-20251109130118861

其他的安装方式可以参考安装文档

k6 的使

k6 的 Hello World

创建一个测试脚本hello-world.js

1
2
3
4
5
6
7
8
import http from 'k6/http';
import { sleep } from 'k6';

export default function () {
  http.get('https://www.baidu.com/');
  // sleep() 函数作为多个串联请求的思考时间
  sleep(1);
}

默认参数运行:

arduino 体验AI代码助手 代码解读复制代码# 默认参数是每个 URL 1 个虚拟用户访问一次
k6 run hello-world.js

模拟 10 个虚拟用户(VU),连续压测 30 秒:

1
k6 run --vus 10 --duration 30s hello-world.js

也可以把这些参数写到脚本里(效果和上面命令行一样):

1
2
3
4
5
6
7
8
9
10
import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
  vus: 10,
  duration: '30s',
};
export default function () {
  http.get('https://www.baidu.com/');
  sleep(1);
}

k6 压测结果数据解读

下面的测试结果是运行上述 hello-world.js测试脚本所得的,测试结果由多个数据汇总而成,下面解读一下各个数据表示什么意思。

image-20251109130212890

  • scenarios:简述测试脚本运行的情况;说明有多少个测试案例、最大的虚拟用户数,最大的运行持续时间。
  • data_received:接收到的数据量大小
  • data_sent:发送的数据量大小
  • http_req_blocked:在发起请求之前被阻塞的时间
  • http_req_connecting:建立到远程主机的 TCP 连接所花费的时间
  • http_req_duration:请求的总时间。它等于 http_req_sending + http_req_waiting + http_req_receiving重要指标
  • http_req_failed:失败请求率
  • http_req_receiving:从远程主机接收响应数据所花费的时间,而没有初始DNS查找/连接时间
  • http_req_sending:将数据发送到远程主机所花费的时间
  • http_req_tls_handshaking:与远程主机握手建立TLS会话所花费的时间
  • http_req_waiting:等待远程主机响应所花费的时间
  • http_reqs:总请求数量TPS
  • iteration_duration:完成默认/主函数的一次完整迭代所花费的时间
  • iterations:脚本中的函数被执行的次数
  • vus:当前活动的虚拟用户数
  • vus_max:虚拟用户的最大数量
  • checks:checks 项的成功率

HTTP Requests

Get 请求

Get 请求的语法是get(url,[params])

1
2
3
4
5
6
7
8
9
10
11
12
import http from 'k6/http';
export let options = {
  vus: 100, // 指定要同时运行的虚拟用户数量
  duration: '10s', // 指定测试运行的总持续时间
};
// default 默认函数
export default function () {
  // 通过 params 设置标头
  let params = { headers: { 'Content-Type': 'application/json' } };
 
  var res=http.get("https://test.k6.io",params)
}

Post 请求

Post 请求的语法是post(url,[body],[params]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import http from 'k6/http';

// 加载本地的文件数据,通过文件数据可以构建动态参数请求了;download the data file here: https://test.k6.io/static/examples/users.json
// 加载的数据不能直接传输给后端,传输给后端需要使用 JSON.stringify() 转换一下
// 若是直接传输给后端就不需要转换成 JSON,也就是省略 JSON.parse() 这部调用
const loginData = JSON.parse(open("./users.json"));

export default function () {
  const url = 'http://test.k6.io/login';
  // Using a JSON string as body
  const payload = JSON.stringify({
    email: 'aaa',
    password: 'bbb',
  });

  const params = {
    headers: {
      'Content-Type': 'application/json',
    },
  };

  http.post(url, payload, params);
}

通用 Request

通用 Request 的语法是request(method,url,[body],[params])

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import http from 'k6/http';

const url = 'https://httpbin.test.k6.io/post';

export default function () {
  const data = { name: 'Bert' };

  // Using a JSON string as body
  let res = http.request('POST', url, JSON.stringify(data), {
    headers: { 'Content-Type': 'application/json' },
  });
  console.log(res.json().json.name); // Bert

  // Using an object as body, the headers will automatically include
  // 'Content-Type: application/x-www-form-urlencoded'.
  res = http.request('POST', url, data);
  console.log(res.json().form.name); // Bert
}

关于 HTTP Requests 更多的请求处理方式请参考HTTP Requests 文档

响应结果断言

一个请求是否正确,需要根据返回结果进行判断,判断请求返回结果一般是使用断言的。k6 必然也是提供响应结果断言检查的,但断言失败不会导致测试中止或以失败状态结束。相反,k6 在测试继续运行时跟踪失败检查的比率。

响应结果结构体可以参考文档Response

检查 HTTP 响应代码

检查非常适合编码与 HTTP 请求和响应相关的断言。例如,此代码段确保 HTTP 响应代码为 200:

1
2
3
4
5
6
7
8
9
import { check } from 'k6';
import http from 'k6/http';

export default function () {
  const res = http.get('http://test.k6.io/');
  check(res, {
    'is status 200': (r) => r.status === 200,
  });
}

当脚本包含检查时,摘要报告会显示通过了多少测试检查:

1
2
3
4
5
6
7
8
k6 run script.js

  ...
     is status 200

  ...
  checks.........................: 100.00% ✓ 1        ✗ 0
  data_received..................: 11 kB   12 kB/s

在此示例中,请注意检查“状态为 200”的调用成功率为 100%。

检查响应正文中的文本

有时,即使是 HTTP 200 响应也包含错误消息。在这些情况下,考虑添加一个检查来验证响应主体,如下所示:

1
2
3
4
5
6
7
8
9
10
import { check } from 'k6';
import http from 'k6/http';

export default function () {
  const res = http.get('http://test.k6.io/');
  check(res, {
    'verify homepage text': (r) =>
      r.body.includes('Collection of simple web-pages suitable for load testing'),
  });
}

若请求结果以 JSON 格式返回,我们可以校验 JSON 对象的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { check } from 'k6';
import http from 'k6/http';

export default function () {
  const res = http.get('http://test.k6.io/');
  /*
  	{
      "status":1,
      "code":"SYS_OK",
      "message":"请求成功!",
      "data":[]
		}
    例如请求返回值是上面的 JSON 对象,所以需要判断 status 字段才能判断请求是否成功。
  */
  // res.json([select]) 可以将响应结果转换为 JSON 对象或 JSON 数组,
  //   通过可选参数 select 获取某个字段值的
  check(res, {
    'status was 200': (r) => r.status == 200,
    'business status was 0': (r) => r.json("status") == 0
  });
}

res.json([select])函数的更多内容可以参考[Response.json( selector] )

检查响应主体大小

要验证响应主体的大小,您可以使用如下检查:

1
2
3
4
5
6
7
8
9
import { check } from 'k6';
import http from 'k6/http';

export default function () {
  const res = http.get('http://test.k6.io/');
  check(res, {
    'body size is 11,105 bytes': (r) => r.body.length == 11105,
  });
}

添加多项检查

您还可以在单个check()语句中添加多个检查:

1
2
3
4
5
6
7
8
9
10
import { check } from 'k6';
import http from 'k6/http';

export default function () {
  const res = http.get('http://test.k6.io/');
  check(res, {
    'is status 200': (r) => r.status === 200,
    'body size is 11,105 bytes': (r) => r.body.length == 11105,
  });
}

执行此测试时,输出将如下所示:

1
2
3
4
5
6
7
8
9
k6 run checks.js

  ...
     is status 200
     body size is 11,105 bytes

  ...
  checks.........................: 100.00%  2         0
  data_received..................: 11 kB   20 kB/s

Option 选项

虚拟用户

Vus:指定要同时运行的虚拟用户数量,必须是一个整数,和 duration 搭配使用。默认值:1

1
2
3
4
5
6
export let options = {
  vus: 10,
  duration: '10s',
};
arduino 体验AI代码助手 代码解读复制代码k6 run -u 10 test.js
k6 run --vus 10 test.js

持续时间

Duration:一个字符串,指定测试运行的总持续时间,与 vus 选项一起使用。默认值:null

1
2
3
4
5
6
export let options = {
  vus: 10,
  duration: '10s',
};
css 体验AI代码助手 代码解读复制代码k6 run -u 10 --d 20s  test.js
k6 run --vus 10 --duration 20s  test.js

模拟多阶段

RPS:每秒发出的最大请求数, 默认值:0;k6 压测默认是并发模式,配置了 RPS 应该调整为吞吐量模式,限定压测的 RPS。

不推荐使用这个选项,因为它有可能不正确;例如,在云端或分布式执行中,此选项独立影响每个 k6 实例。也就是说,它不像 VU 那样被分片。我们强烈建议到达率执行器模拟恒定 RPS,而不是这个选项。

1
2
3
ini 体验AI代码助手 代码解读复制代码export let options = {
  rps: 500,
};

模拟多测试阶段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  stages: [
    { duration: '30s', target: 20 },
    { duration: '1m30s', target: 10 },
    { duration: '20s', target: 0 },
  ],
};

export default function () {
  const res = http.get('https://www.baidu.com/');
  check(res, { 'status was 200': (r) => r.status == 200 });
  sleep(1);
}

前 30 秒,用户从 0 增涨到 20。然后接下来的 1 分 30 秒,持续模拟 10 个用户。然后用 20 秒的时间,把并发用户数从 10 减少到 0。

趋势汇总统计

k6 默认的趋势汇总统计格式是:avg,min,med,max,p(90),p(95),我们可以自定义趋势汇总统计,例如我们需要关注p(99)这个指标,那么我们可以自定义summaryTrendStats的值:

# 添加 p(99) 指标
export const options = {
    summaryTrendStats: ['avg', 'min', 'med', 'max', 'p(90)','p(95)', 'p(99)']
  }

日志输出

输出到控制台:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import http from 'k6/http';
export let options = {
  vus: 10,
  duration: '2s',
};

export default function () {
  let res = http.get('http://www.baidu.com');
   console.log('log')
   console.info('info');
   console.error('err');
   console.debug('debug')
   console.warn('warn')
}

输出到文件,输出到文件的同时控制台不再输出:

1
 run  test.js --console-output=test.log

k6 测试结果的可视化

通过 http://127.0.0.1:5665 我们可以在本地浏览器实时查看接口测试情况。

image-20251109130245631

参考

k6 官网

k6-像单元测试一样做压力测试

使用 K6 来给你的服务做一次负载和压力测试吧(参考价值大)

使用k6.io进行性能测试与压力测试,并生成优雅的可视化报告

© 2024- lfj