Grafana k6 是一款现代化的开源性能测试工具,专为测试API、微服务和网站而设计。
它采用JavaScript/TypeScript作为脚本语言,提供了简洁的API和强大的负载模拟能力,同时易于集成到CI/CD流程中。
本文将带您从基础到进阶,全面掌握k6的使用方法。
一、安装与环境准备
1.1 支持的操作系统
k6支持Windows、macOS和Linux,同时提供Docker镜像,方便在任何环境中运行。
1.2 安装步骤
macOS (Homebrew):
bash
brew install k6
Windows (Chocolatey):
bash
choco install k6
Linux (Ubuntu/Debian):
bash
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C3959F7F5288
echo "deb https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list
sudo apt update && sudo apt install k6
Docker:
bash
docker pull grafana/k6
1.3 验证安装
安装完成后,运行以下命令验证:
bash
k6 version
如果安装成功,会显示类似以下内容:
k6 v0.49.0 ((devel), go1.21.0, linux/amd64)
二、k6核心概念
在编写测试脚本前,理解k6的核心概念至关重要:
-
虚拟用户(VUs): 模拟真实用户的并发单元,每个VU独立执行脚本逻辑
-
场景(Scenarios): 定义测试的负载模式,如并发数、持续时间、递增方式等
-
生命周期:
init
阶段: 脚本最外层代码,只执行一次,用于导入模块和定义全局变量setup
函数: 测试开始前执行一次,用于准备测试数据VU
函数: 每个虚拟用户重复执行的核心测试逻辑teardown
函数: 测试结束后执行一次,用于清理测试环境
-
指标(Metrics): 衡量系统性能的数据,如响应时间、错误率等
-
检查(Checks): 验证系统响应是否符合预期的断言机制
-
阈值(Thresholds): 定义性能指标的可接受范围,用于自动判断测试是否通过
三、第一个k6测试脚本
让我们从一个简单的HTTP GET请求测试开始,创建文件basic-test.js
:
javascript
import http from 'k6/http';
import { check, sleep } from 'k6';
// 测试配置选项
export const options = {
vus: 10, // 并发虚拟用户数
duration: '30s', // 测试持续时间
};
// 虚拟用户执行的主要函数
export default function() {
// 发送GET请求
const res = http.get('https://httpbin.test.k6.io/get');
// 检查响应是否符合预期
check(res, {
'状态码为200': (r) => r.status === 200,
'响应时间小于500ms': (r) => r.timings.duration < 500,
});
// 每个迭代后暂停1秒,模拟用户思考时间
sleep(1);
}
3.1 脚本解析
-
导入模块 : 我们导入了
http
模块用于发送HTTP请求,check
用于验证响应,sleep
用于模拟用户等待时间。 -
配置选项:
vus
: 同时运行的虚拟用户数量duration
: 测试总持续时间
-
VU函数:
http.get()
: 发送HTTP GET请求到指定URLcheck()
: 验证响应状态码和响应时间sleep(1)
: 暂停1秒,避免请求过于密集
3.2 运行测试
执行以下命令运行测试:
bash
k6 run basic-test.js
如果使用Docker,执行:
bash
cat script.js | docker run --rm -i grafana/k6 run -
四、测试结果分析
测试运行时和结束后,k6会输出详细的测试结果。让我们理解一些关键指标:
█ TOTAL RESULTS
checks_total.......: 440 14.035254/s
checks_succeeded...: 100.00% 440 out of 440
checks_failed......: 0.00% 0 out of 440
✓ ???????00
✓ ?????????500ms
HTTP
http_req_duration..............: avg=188.19ms min=60.93ms med=193.8ms max=338.83ms p(90)=309.64ms p(95)=310.83ms
{ expected_response:true }...: avg=188.19ms min=60.93ms med=193.8ms max=338.83ms p(90)=309.64ms p(95)=310.83ms
http_req_failed................: 0.00% 0 out of 440
http_reqs......................: 440 14.035254/s
EXECUTION
iteration_duration.............: avg=1.41s min=1.36s med=1.37s max=2.26s p(90)=1.38s p(95)=1.4s
iterations.....................: 220 7.017627/s
vus............................: 10 min=10 max=10
vus_max........................: 10 min=10 max=10
NETWORK
data_received..................: 772 kB 25 kB/s
data_sent......................: 30 kB 958 B/s
关键指标解释:
- http_req_duration : HTTP请求的总持续时间,包含了建立连接、发送请求、等待响应和接收响应的时间
p(90)
和p(95)
是百分位数,表示90%或95%的请求在此时间内完成
- http_req_failed: 失败请求的比例,理想情况下应为0
- http_reqs: 每秒处理的请求数(RPS),反映系统吞吐量
- vus: 当前并发虚拟用户数
- iterations: 完成的测试迭代次数
五、进阶测试场景
5.1 复杂场景配置
k6的场景(Scenarios)功能允许您定义更复杂的负载模式。创建scenarios-test.js
:
javascript
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
scenarios: {
// 场景1: 逐步增加负载
ramp_up: {
executor: 'ramping-vus',
startVUs: 0,
stages: [
{ duration: '30s', target: 50 }, // 30秒内从0增加到50个VU
{ duration: '1m', target: 50 }, // 维持50个VU 1分钟
{ duration: '20s', target: 0 }, // 20秒内减少到0个VU
],
gracefulRampDown: '10s', // 优雅地减少负载
},
// 场景2: 恒定负载
constant_load: {
executor: 'constant-vus',
vus: 20,
duration: '2m',
startTime: '1m50s', // 在第一个场景开始后1分50秒启动
},
},
};
export default function() {
const res = http.get('https://httpbin.test.k6.io/get');
check(res, {
'状态码为200': (r) => r.status === 200,
});
sleep(1);
}
k6提供多种执行器(executor)类型,适用于不同测试场景:
ramping-vus
: 逐步增加或减少虚拟用户数constant-vus
: 维持恒定的虚拟用户数constant-arrival-rate
: 维持恒定的请求率ramping-arrival-rate
: 逐步增加或减少请求率per-vu-iterations
: 每个虚拟用户执行固定次数的迭代
5.2 设置阈值(Thresholds)
阈值用于定义性能指标的可接受范围,创建thresholds-test.js
:
javascript
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 10,
duration: '30s',
thresholds: {
// 错误率必须小于1%
http_req_failed: ['rate<0.01'],
// 95%的请求响应时间必须小于500ms
http_req_duration: ['p(95)<500'],
// 每秒请求数至少为10
http_reqs: ['rate>10'],
},
};
export default function() {
const res = http.get('https://httpbin.test.k6.io/get');
check(res, {
'状态码为200': (r) => r.status === 200,
});
sleep(1);
}
如果任何阈值未达标,k6将以非零状态码退出,这在CI/CD集成中非常有用。
5.3 处理认证与状态保持
大多数API测试需要处理认证,创建auth-test.js
:
javascript
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 5,
duration: '30s',
};
// 测试开始前执行一次,用于登录获取token
export function setup() {
const loginRes = http.post('https://test-api.k6.io/auth/token/login/', {
username: 'test-user',
password: 'test-passwd',
});
const token = loginRes.json('access');
check(loginRes, {
'登录成功': (r) => r.status === 200 && token !== '',
});
return { token: token };
}
// 每个虚拟用户执行的测试逻辑
export default function(data) {
const params = {
headers: {
Authorization: `Bearer ${data.token}`,
'Content-Type': 'application/json',
},
};
// 访问受保护的API端点
const res = http.get('https://test-api.k6.io/my/crocodiles/', params);
check(res, {
'状态码为200': (r) => r.status === 200,
'响应包含鳄鱼数据': (r) => JSON.parse(r.body).length > 0,
});
sleep(1);
}
// 测试结束后执行一次,用于清理
export function teardown(data) {
const params = {
headers: {
Authorization: `Bearer ${data.token}`,
},
};
// 登出(如果API支持)
const res = http.post('https://test-api.k6.io/auth/token/logout/', null, params);
check(res, {
'登出成功': (r) => r.status === 204,
});
}
这个脚本展示了如何:
- 在
setup
函数中执行登录并获取认证token - 将token传递给VU函数
- 在每个请求中使用token进行认证
- 在
teardown
函数中执行登出清理
5.4 测试数据管理
对于更真实的测试,我们需要使用不同的测试数据。创建data-driven-test.js
:
javascript
import http from 'k6/http';
import { check, sleep, SharedArray } from 'k6';
import { Counter } from 'k6/metrics';
// 自定义指标,用于跟踪不同类型的请求
const successfulSearches = new Counter('successful_searches');
const failedSearches = new Counter('failed_searches');
// 从JSON文件加载测试数据(只在init阶段执行一次)
const data = new SharedArray('搜索关键词', function() {
return JSON.parse(open('./search-terms.json')).terms;
});
export const options = {
vus: 10,
duration: '30s',
thresholds: {
http_req_duration: ['p(95)<500'],
successful_searches: ['rate>0.95'],
},
};
export default function() {
// 为每个VU选择不同的关键词(基于VU ID和迭代次数)
const term = data[(__VU * __ITER) % data.length];
// 发送搜索请求
const res = http.get(`https://httpbin.test.k6.io/get?search=${encodeURIComponent(term)}`);
// 检查响应
const isSuccessful = check(res, {
'状态码为200': (r) => r.status === 200,
'响应包含搜索词': (r) => r.body.includes(term),
});
// 更新自定义指标
if (isSuccessful) {
successfulSearches.add(1);
} else {
failedSearches.add(1);
}
sleep(1);
}
创建配套的search-terms.json
文件:
json
{
"terms": ["k6", "performance", "testing", "api", "grafana", "load", "stress", "vus", "thresholds", "scenarios"]
}
这个脚本展示了:
- 使用
SharedArray
高效加载和共享测试数据 - 为不同的虚拟用户分配不同的测试数据
- 创建和使用自定义指标
六、结果导出与可视化
6.1 导出结果到文件
k6可以将测试结果导出为多种格式:
bash
# 导出为JSON
k6 run --out json=results.json basic-test.js
# 导出为CSV
k6 run --out csv=results.csv basic-test.js
# 同时导出多种格式
k6 run --out json=results.json --out csv=results.csv basic-test.js
6.2 与Grafana集成
将k6与Grafana集成可以获得更强大的可视化和分析能力:
- 启动InfluxDB(作为数据存储):
bash
docker run -d -p 8086:8086 \
-e INFLUXDB_DB=k6 \
--name influxdb \
influxdb:1.8
- 启动Grafana:
bash
docker run -d -p 3000:3000 \
--link influxdb:influxdb \
--name grafana \
grafana/grafana
-
在Grafana中配置数据源:
- 访问http://localhost:3000(默认用户名/密码:admin/admin)
- 添加InfluxDB数据源,URL设置为http://influxdb:8086,数据库名为k6
-
导入k6官方仪表板:
- 在Grafana中导入仪表板ID:1443
- 选择配置好的InfluxDB数据源
-
运行测试并发送结果到InfluxDB:
bash
k6 run --out influxdb=http://localhost:8086/k6 basic-test.js
现在,您可以在Grafana中实时查看测试指标和图表。
七、CI/CD集成
k6可以轻松集成到CI/CD流程中,作为质量门禁的一部分。以下是GitHub Actions的配置示例(创建.github/workflows/k6-test.yml
):
yaml
name: k6 Performance Test
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
k6-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup k6
uses: k6io/action@v0.1
with:
k6-version: latest
- name: Run k6 test
run: k6 run tests/load-test.js
- name: Upload test results
if: always()
uses: actions/upload-artifact@v3
with:
name: k6-results
path: results.json
这个配置将在每次推送到main分支或创建PR时自动运行k6测试,如果测试失败(阈值未达标),CI流程也会失败。
八、最佳实践
-
从简单开始: 先创建基础测试,验证基本功能,再逐步增加复杂度
-
使用真实数据: 测试数据应尽可能接近生产环境的真实数据
-
定义明确的阈值: 根据业务需求和SLA定义清晰的性能阈值
-
逐步增加负载: 从低负载开始,逐步增加,观察系统在不同负载下的表现
-
隔离测试环境: 确保测试环境与生产环境隔离,避免影响真实用户
-
监控系统资源: 在测试期间监控服务器CPU、内存、磁盘I/O等资源使用情况
-
版本控制测试脚本: 将测试脚本纳入版本控制,与应用代码一起演进
-
自动化测试: 将性能测试集成到CI/CD流程中,尽早发现性能问题
-
分析瓶颈: 不仅关注响应时间,还要分析系统瓶颈所在(数据库、网络、应用服务器等)
-
定期执行: 定期运行性能测试,跟踪性能变化趋势
九、总结
通过本教程,您已经掌握了Grafana k6的核心功能和使用方法,包括:
- 安装和配置k6环境
- 理解k6的核心概念和生命周期
- 编写基础和进阶的测试脚本
- 配置复杂的测试场景和阈值
- 处理认证和管理测试数据
- 导出和可视化测试结果
- 集成k6到CI/CD流程
k6提供了丰富的功能和灵活的API,能够满足从简单到复杂的各种性能测试需求。随着您对k6的深入使用,可以探索更多高级功能,如自定义指标、WebSocket测试、分布式测试等。
要了解更多信息,请参考k6官方文档:https://k6.io/docs/