1、创建新的测试脚本
k6 new //创建一个新的测试脚本,不指定文件名,默认文件名为script.js
k6 new my-test.js //指定文件名称的方式
k6 run script.js //运行文件
2、运行测试脚本
k6 run --vus 10 --duration 30s script.js //运行时同时指定虚拟用户数量和运行时间
k6 run script.js //不指定使用文件里面的默认配置
3、K6的生命周期
在k6测试的生命周期中,脚本会按照以下顺序依次执行各个阶段:
import http from 'k6/http';
import { sleep, check } from 'k6';
export let options = {
stages: [
{ duration: '10s', target: 100 }, // 预热阶段
{ duration: '1m', target: 100 }, // 稳定负载阶段
{ duration: '10s', target: 0 }, // 降温阶段
],
thresholds: { // 定义性能指标阈值
http_req_duration: ['p(95)<200'], // 95%的请求应在200毫秒内完成
},
};
定义一些全局变量用于测试中复用
let baseURL = 'https://test.k6.io/';
//以上内容属于k6脚本中init内容,会最先执行
// 接下来,如果定义了`setup`函数,它将运行。这个阶段主要用于测试环境的准备工作,比如建立数据库连接、初始化测试数据等。此阶段是可选的。
export function setup() {
}
// 紧接着,脚本的核心部分——默认函数(`default`函数)或特定场景函数开始执行。这些函数定义了每个虚拟用户(VU)需要执行的具体操作,如发送HTTP请求、记录性能指标等。它们会根据测试选项中设定的持续时间和迭代次数来执行。这是测试的主要部分,是必选的。
export default function (data) {
}
// 清理函数(Teardown Function): 测试结束阶段,如果定义了teardown函数,则会执行该函数。此阶段主要用于清理测试过程中使用的资源,比如关闭打开的连接、保存测试结果到文件等。这也是一个可选阶段
export function teardown(data) {
}
4、数据传递
4.1、在k6中有两种主要方式来定义和使用数据
全局变量:你可以在脚本的顶层定义变量,这些变量对整个脚本都是可见的,包括setup、default、teardown等所有部分。这种方式简单直接,但要注意,全局变量在所有VU间是共享的,可能导致并发访问的问题
通过setup函数传递数据:这是更推荐的做法,尤其是在需要初始化数据或为每个VU提供独立数据副本的场景中。setup函数只运行一次,其返回值会被传递给每个VU的执行上下文(如default函数
4.2、示例
let baseURL = 'https://test.k6.io/';
export function setup() {
console.log("setup设置函数执行了")
return { v:1 }
}
export default function(data) {
console.log("default vu 函数执行了")
console.log(baseURL)
console.log(JSON.stringify(data))
console.log("default vu 函数执行了")
}
export function teardown(data) {
console.log("拆卸函数执行了")
console.log(JSON.stringify(data))
console.log("拆卸函数执行了")
}
5、设置项
//固定用户数,固定运行时间
export const options = {
vus: 10,
duration: '3s',
}
//## 分阶段上下倾斜VUs
export const options = {
stages: [
{ duration: '30s', target: 20 },
{ duration: '1m30s', target: 10 },
{ duration: '20s', target: 0 },
],
};
在脚本设置之后直接生效
6、场景
// options 对象是k6脚本中定义测试配置的中心点,它允许你控制测试的各种方面,如持续时间、虚拟用户数量(VUs)、迭代次数等
export const options = {
// scenarios 是options对象的一个属性,用于定义一个或多个测试场景。每个场景定义了不同的测试策略,比如负载模式、执行器类型等
scenarios: {
// 自定义场景
scenarios_1: {
// 指定了执行该场景所使用的执行器类型。shared-iterations 执行器意味着所有的VUs将共享一个迭代池,即所有VU共同完成指定的迭代次数(200次)
executor: 'shared-iterations',
// 设置了该场景开始执行的时间点,相对于测试启动时间延迟10秒开始
startTime: '10s',
// 测试优雅停止的时间,即在达到最大持续时间或完成所有迭代后,k6会等待5秒以确保所有正在进行的请求完成,而不是立即终止,如果没有显式设置,此值默认等于30
gracefulStop: '5s',
// 指定了参与该场景的虚拟用户数量为10
vus: 10,
//表示在这个场景下,所有虚拟用户(VUs)共同需要完成的总迭代次数为200次。这里的重点在于“总迭代次数”,意味着所有VU加起来一共执行200次请求或任务。
iterations: 200,
// 设置了场景的最大持续时间为10秒。这意味着无论迭代是否完成,场景都会在达到10秒后结束执行。
maxDuration: '10s',
//给当前场景设置环境变量
env: { EXAMPLEVAR: 'testing' },
//当前场景设置tag
tags: { example_tag: 'testing' }
}
}
}
6.1、场景执行器
shared-iterations
执行器允许所有虚拟用户(VUs)共享一个迭代池,一起完成指定数量的迭代。这意味着所有VU作为一个团队工作,共同完成一个固定的总迭代次数,而不是每个VU单独完成自己的迭代次数。
示例:
import http from 'k6/http'
import { sleep } from 'k6'
//定义测试配置
export let options = {
scenarios: {
sharedIterationExample:{
// 使用shared-iterations执行器,定义场景必填项
executor: 'shared-iterations',
// 启动5个虚拟用户
vus: 5,
// 总共执行100次迭代
iterations: 100,
// 测试最大持续时间为30秒
maxDuration: '30s',
}
}
}
//默认函数,每一个vu按照配置执行
export default function (){
http.get('https://test.k6.io/contacts.php')
// 模拟用户操作间的延迟
sleep(0.1)
}
组合执行器
import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
scenarios: {
shared_iter_scenario: {
executor: "shared-iterations",
vus: 10,
iterations: 100,
startTime: "0s",
},
per_vu_scenario: {
executor: "per-vu-iterations",
vus: 10,
iterations: 10,
startTime: "10s",
},
},
};
// 第一个场景在0秒开始,每个VU参与共享完成100次迭代。
// 第二个场景在10秒开始,每个VU执行10次迭代。
// VU是作为可复用资源在场景之间共享
// 示例请求函数
export default function() {
http.get("https://test.k6.io/contacts.php")
console.log("执行了")
sleep(1); // 模拟请求间延迟
}
7、开放模型和封闭模型
7.1封闭模型、
- 在封闭模型中,虚拟用户的迭代是按顺序进行的,每个虚拟用户的迭代必须等待上一个虚拟用户的迭代完成后才能开始。
- 封闭模型适用于那些需要逐步增加负载、需要严格控制并发用户数量或者需要验证系统在负载逐步增加时的稳定性的压测场景
import http from 'k6/http';
import { sleep } from 'k6';
export let options = {
vus: 5, // 设置虚拟用户数为5
duration: '60s', // 测试持续时间为60秒
};
export default function() {
http.get('https://test.k6.io/contacts.php'); // 发起HTTP GET请求
sleep(1); // 模拟用户操作之间的延迟,这里简单设置为1秒
}
7.2开放模型、
- 在开放模型中,虚拟用户的到达是独立于其执行的,即使某个虚拟用户的请求尚未完成,新的虚拟用户也可以随时到达并开始执行其任务。
- 开放模型适用于需要模拟高并发负载、快速达到目标负载或评估系统吞吐量的压测场景。
import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
stages: [
// 运行5分钟,每秒启动10个虚拟用户 (VUs),总共启动300个
{ duration: '5m', target: 10 },
// 维持10分钟,每秒发送10个请求,这是constant-arrival-rate的核心设置部分
{ duration: '10m', target: 10, rps: 10 },
// 渐进降低到0,清理阶段
{ duration: '5m', target: 0 },
],
};
export default function () {
const url = 'https://test.k6.io/contacts.php'
const res = http.get(url);
console.log(`Response status code: ${res.status}`);
sleep(1); // 模拟请求之间的延迟,默认是不睡眠的,根据实际情况调整
}
8、多阶段测试平滑过渡
- 针对
ramping-vus执行器 - 用于多stage测试过程
- 用于高负债平滑过渡到低负载
export const options = {
stages: [
// 预热阶段,逐渐增加到50个VU
{ duration: '5m', target: 50 },
// 高峰负载阶段,保持100个VU
{ duration: '10m', target: 100 },
// 逐步减少阶段,目标降至25个VU,这里应用了gracefulRampDown
{ duration: '5m', target: 25, gracefulRampDown: '2m' }, // 设定2分钟的平滑减少时间
]
};
如果设置了gracefulRampDown,意味着在降载阶段(即VU数量减少的阶段),k6会给VU提供最多2分钟的时间来自然完成它们当前正在进行的迭代。如果某个VU的迭代在2分钟后仍未完成,k6将会强制中断该VU。gracefulRampDown参数的使用可以提高测试的现实性和准确性,特别是在模拟用户逐渐离开系统的场景时,有助于减少因突然关闭大量VU而可能引入的测试偏差或系统负担。
如果不设置gracefulRampDown,在降载阶段,一旦VU的数量需要减少,k6会在达到新阶段的目标VU数时立即停止超出数量的VU,而不会给予额外的时间让这些VU完成其正在进行的迭代。这可能会导致一些正在进行中的事务或请求被突然中断,对于某些应用场景来说,这样的中断可能会对测试结果的准确性产生影响,或者在被测试系统中留下未完成的操作,比如未关闭的数据库连接等。
9、例子
import http from 'k6/http';
import { sleep } from 'k6';
export const options = {
scenarios: {
my_web_test: {
executor: 'constant-vus',
vus: 50,
duration: '5m',
gracefulStop: '0s',
tags: { test_type: 'website' },
exec: 'webtest',
},
my_api_test_1: {
executor: 'constant-arrival-rate',
rate: 90,
timeUnit: '1m',
duration: '5m',
preAllocatedVUs: 10,
tags: { test_type: 'api' },
env: { MY_CROC_ID: '1' },
exec: 'apitest',
},
my_api_test_2: {
executor: 'ramping-arrival-rate',
startTime: '30s',
startRate: 50,
timeUnit: '1s',
stages: [
{ target: 200, duration: '30s' },
{ target: 200, duration: '3m30s' },
{ target: 0, duration: '30s' },
],
preAllocatedVUs: 50,
maxVUs: 100,
tags: { test_type: 'api' },
env: { MY_CROC_ID: '2' },
exec: 'apitest',
},
},
/**
* 用于告知k6性能测试工具在测试执行期间是否应该丢弃HTTP请求的响应体。当设置为true时,k6在收到服务器响应后,将不会保留响应的内容,仅保留响应的元数据,如状态码、头部信息等
* 减少内存占用:在进行大规模负载测试时,响应体可能是非常大的,尤其是当请求下载大文件或大量数据时。不存储响应体可以显著减少测试过程中消耗的内存资源,允许在有限的系统资源下运行更大规模的测试。
* 提高测试效率:丢弃响应体可以减少处理响应数据所需的时间,尤其是在测试专注于请求吞吐量和延迟等性能指标,而非响应内容本身时,这可以加快测试执行速度。
* 简化测试重点:有时测试目的主要是验证服务的可用性和响应时间,而不是响应数据的正确性。在这种情况下,保留响应体是没有必要的,使用此选项可以帮助聚焦于性能指标的测试。
* 需要注意的是,如果测试逻辑中需要验证响应的具体内容,比如检查返回的数据是否正确,那么就不能使用discardResponseBodies: true,因为这会导致无法访问响应数据进行验证。
*/
discardResponseBodies: true,
// thresholds的作用在于设置一系列性能指标的期望值或容许范围,比如响应时间、吞吐量、错误率等,用以评估系统在压力或负载条件下的表现是否在可接受范围内。
// 当实际测试结果超出这些阈值时,虽然k6测试本身不会因此直接中止,但这些超出阈值的情况会被记录并在测试报告中高亮显示,便于分析和后续的性能调优。
thresholds: {
'http_req_duration{test_type:api}': ['p(95)<250', 'p(99)<350'],
'http_req_duration{test_type:website}': ['p(99)<500'],
'http_req_duration{scenario:my_api_test_2}': ['p(99)<300'],
},
};
export function webtest() {
http.get('https://test.k6.io/contacts.php');
sleep(Math.random() * 2);
}
export function apitest() {
// https://test-api.k6.io/public/crocodiles/2}
http.get(`https://test-api.k6.io/public/crocodiles/${__ENV.MY_CROC_ID}/`);
}
10、测试结果
好几种方式
- 本地根据json文件生成
- 使用 k6 cloud
- 等等
本次使用k6 cloud
k6 login cloud --token 599bb16e913fc9917c
k6 run --out cloud ConstantVUs.js
生成图表见下图