4. k6 核心 API:http.get、http.post、check、group、sleep、metrics(自定义指标)
k6 脚本的核心是 JavaScript 代码与 k6 内置 API 的交互。本章将深入剖析压测脚本中最常用的六个核心 API:http.get、http.post、check、group、sleep 以及自定义指标(metrics)。掌握这些 API 是编写复杂、可观测的多阶段压测场景的基础。
核心原则:k6 的 API 设计遵循“同步阻塞”模型。每个 HTTP 请求都是同步的,直到收到响应或超时才会执行下一行代码。这使得脚本逻辑清晰,易于理解和调试。
4.1 HTTP 请求:http.get 与 http.post
http.get(url, [params]) 和 http.post(url, body, [params]) 是发起 HTTP 请求的基石。它们返回一个 Response 对象,包含状态码、响应体、头部、耗时等信息。
| API | 必填参数 | 可选参数 (params 对象) | 典型返回值 |
|---|---|---|---|
http.get(url) |
url (字符串) |
tags, headers, timeout, params.auth 等 |
Response 对象 |
http.post(url, body) |
url (字符串), body (字符串/对象) |
tags, headers, timeout, params.auth 等 |
Response 对象 |
import http from 'k6/http';
export default function () {
// GET 请求
let getRes = http.get('https://test-api.example.com/users');
console.log(`GET status: ${getRes.status}`);
// POST 请求,发送 JSON 数据
let payload = JSON.stringify({ name: 'k6-user', role: 'tester' });
let params = {
headers: { 'Content-Type': 'application/json' },
tags: { my_custom_tag: 'user-creation' }, // 用于指标标记
};
let postRes = http.post('https://test-api.example.com/users', payload, params);
console.log(`POST status: ${postRes.status}`);
}
关键参数:
params.tags 允许你为每个请求打上自定义标签,这在后续分析指标(如按标签过滤请求耗时)时至关重要,是实现精细化 SLO 监控的基础。
4.2 断言与验证:check
check 函数用于对响应结果进行断言。它不会中断脚本执行,但会记录断言的成功/失败次数,并暴露为内置指标 checks 和 checks_failed。这是实现 SLO 门禁中“功能正确性”验证的核心。
import { check } from 'k6';
import http from 'k6/http';
export default function () {
let res = http.get('https://test-api.example.com/health');
// 使用 check 进行多项断言
check(res, {
'status is 200': (r) => r.status === 200,
'response body has "ok"': (r) => r.body.includes('ok'),
'response time < 500ms': (r) => r.timings.duration < 500,
});
}
| check 特性 | 说明 |
|---|---|
| 非阻塞 | 断言失败不会抛出异常,脚本继续执行后续逻辑。 |
| 内置指标 | 每次 check 结果自动记录到 checks (通过数) 和 checks_failed (失败数) 指标。 |
| 分组统计 | 与 group 结合使用,可以按业务模块查看断言通过率。 |
4.3 业务逻辑分组:group
group(name, func) 用于将相关的操作(如多个 HTTP 请求、多个 check)组织到一个逻辑分组中。分组不会影响执行顺序,但会在最终报告中按组聚合指标(如请求耗时、吞吐量),极大提升报告的可读性。
import { group } from 'k6';
import http from 'k6/http';
export default function () {
group('用户登录流程', function () {
let loginRes = http.post('https://test-api.example.com/login', { user: 'test', pass: '123' });
check(loginRes, { 'login success': (r) => r.status === 200 });
});
group('获取用户资料', function () {
let profileRes = http.get('https://test-api.example.com/profile');
check(profileRes, { 'profile fetched': (r) => r.status === 200 });
});
}
注意:
group 是纯逻辑分组,不提供事务回滚或隔离能力。它主要用于报告聚合和指标标记,不要将其与数据库事务或编程语言中的 try-catch 混淆。
4.4 用户思考时间:sleep
sleep(t) 函数用于模拟真实用户在操作之间的“思考时间”或“等待时间”。参数 t 是以秒为单位的浮点数。合理使用 sleep 可以避免压测流量过于集中,使负载模型更接近真实场景。
import { sleep } from 'k6';
export default function () {
// 模拟用户浏览首页
http.get('https://test-api.example.com/');
sleep(1); // 思考 1 秒
// 模拟用户搜索
http.get('https://test-api.example.com/search?q=k6');
sleep(2.5); // 思考 2.5 秒
// 模拟用户提交表单
http.post('https://test-api.example.com/order', { item: 'book' });
sleep(0.5);
}
最佳实践:使用随机化的思考时间(如
sleep(Math.random() * 3 + 1))可以更真实地模拟用户行为,避免所有虚拟用户同时发起请求。
4.5 自定义指标:metrics
除了 k6 内置的指标(如 http_req_duration, vus),你可以通过 metrics 模块创建自定义指标,用于监控业务层面的特定数据,例如:数据库查询耗时、缓存命中率、业务错误码计数等。自定义指标是实现精细化 SLO 监控的关键。
k6 支持四种自定义指标类型:
| 指标类型 | 构造函数 | 适用场景 | 聚合方式 |
|---|---|---|---|
| Counter | new Counter(name) |
计数类,如错误次数、请求总数 | 求和 |
| Gauge | new Gauge(name) |
瞬时值,如当前连接池大小、队列深度 | 最小值/最大值/最后值 |
| Rate | new Rate(name) |
比率类,如成功率、缓存命中率 | 通过数/总数 |
| Trend | new Trend(name) |
分布类,如数据库查询耗时、响应体大小 | 最小值/最大值/平均值/百分位数 |
import { Counter, Trend } from 'k6/metrics';
import http from 'k6/http';
// 定义自定义指标
let myErrorCounter = new Counter('my_business_errors');
let myDbQueryDuration = new Trend('my_db_query_duration', true); // true 表示启用百分位计算
export default function () {
let res = http.get('https://test-api.example.com/data');
// 模拟记录业务错误
if (res.status !== 200) {
myErrorCounter.add(1); // 增加计数
}
// 模拟记录数据库查询耗时(假设从响应头中获取)
let dbTime = parseFloat(res.headers['X-DB-Query-Time'] || '0');
myDbQueryDuration.add(dbTime); // 记录耗时分布
}
SLO 门禁集成:自定义指标可以直接在
thresholds 中使用。例如,你可以设置一个 SLO 门禁规则:thresholds: { 'my_business_errors': ['count<10'] },确保在压测期间业务错误总数不超过 10 个。
4.6 综合示例:多阶段压测脚本
以下示例整合了所有核心 API,展示了一个典型的多阶段压测脚本结构:
import http from 'k6/http';
import { check, group, sleep } from 'k6';
import { Counter, Trend } from 'k6/metrics';
let businessErrors = new Counter('business_errors');
let orderTrend = new Trend('order_processing_time');
export const options = {
stages: [
{ duration: '30s', target: 20 },
{ duration: '1m', target: 20 },
{ duration: '30s', target: 0 },
],
thresholds: {
http_req_duration: ['p(95)<2000'],
business_errors: ['count<5'],
},
};
export default function () {
group('浏览商品', function () {
let res = http.get('https://test-api.example.com/products');
check(res, { 'products page loaded': (r) => r.status === 200 });
sleep(Math.random() * 2 + 1);
});
group('下单流程', function () {
let startTime = Date.now();
let orderRes = http.post('https://test-api.example.com/orders', JSON.stringify({ item: 'laptop' }), {
headers: { 'Content-Type': 'application/json' },
});
let duration = Date.now() - startTime;
orderTrend.add(duration);
if (orderRes.status !== 201) {
businessErrors.add(1);
}
check(orderRes, { 'order created': (r) => r.status === 201 });
sleep(1);
});
}
本章小结:
http.get/post 发起请求,check 验证结果,group 组织逻辑,sleep 模拟思考,metrics 自定义业务指标。这五个 API 构成了 k6 压测脚本的骨架,是后续实现复杂场景和 SLO 门禁的基石。