编程 k6:用 JavaScript 写压测脚本,把 SLO 断言放进 CI

2026-09-16 00:05:11

k6:用 JavaScript 写压测脚本,把 SLO 断言放进 CI

k6 是 Grafana 维护的负载测试工具,定位一句话:像写单元测试一样写性能测试。项目地址在 github.com/grafana/k6,完整文档在 grafana.com/docs/k6/latest

它是什么,不是什么

k6 本身用 Go 编写,发布形态是单个二进制文件,装完直接 k6 run script.js,不需要额外运行时或依赖服务。压测脚本用 JavaScript 写,但跑在 k6 内嵌的 JS 引擎里,不是 Node 环境——import 进来的是 k6 自带模块(如 k6/http)和扩展模块,不涉及 npm 生态。

这个组合的实际意义:Go 侧负责并发调度和网络 I/O,脚本侧保留 JavaScript 的写法习惯。测试因此是代码——可以复用、拆模块、进版本控制、接 CI,而不是在 GUI 里点出来的配置。

README 里列出的核心能力包括:可配置的负载生成(低配机器也能模拟大量流量)、脚本即代码、功能完整的脚本 API、内嵌 JS 引擎、多协议支持、扩展生态,以及灵活的指标存储与可视化(汇总统计或细粒度指标导出到你选的后端)。另外还有与 Grafana Cloud 的原生集成,用于测试执行、指标关联和数据分析。

一个脚本里的关键机制

官方示例脚本:

import http from "k6/http";
import { check, sleep } from "k6";

// Test configuration
export const options = {
  thresholds: {
    // Assert that 99% of requests finish within 3000ms.
    http_req_duration: ["p(99) < 3000"],
  },
  // Ramp the number of virtual users up and down
  stages: [
    { duration: "30s", target: 15 },
    { duration: "1m", target: 15 },
    { duration: "20s", target: 0 },
  ],
};

// Simulated user behavior
export default function () {
  let res = http.get("https://quickpizza.grafana.com");
  // Validate response status
  check(res, { "status was 200": (r) => r.status == 200 });
  sleep(1);
}

拆开看几块内容。

thresholds:把 SLO 写成断言

options.thresholds 里声明的是通过/不通过的标准。上面这条 http_req_duration: ["p(99) < 3000"] 表示 99% 的请求耗时必须低于 3000ms(单位毫秒)。阈值不满足时,测试结果判定为失败,k6 run 会以非零退出码结束——这一点决定了它能不能直接当 CI 门禁用。阈值可以基于任意指标组合,也可以表达更复杂的条件,详见 Thresholds 文档(链接见文末)。

stages:渐进加压

stages 定义虚拟用户(VU)数量随时间变化的曲线。例子里的三段分别是:30 秒内升到 15 个 VU、维持 1 分钟、再用 20 秒降到 0。这样能观察系统在爬坡、稳态、退坡三个阶段的表现,而不是一上来就打满。加压曲线怎么设计取决于你要验证的场景,压满值也不是越高越好,需要结合目标环境容量自行验证。

check() 与 sleep():业务断言和节奏控制

check(res, { "status was 200": (r) => r.status == 200 }) 是对单个响应做业务层校验,比如状态码、响应体字段。检查失败不会中断测试,但会记录到结果里,用于统计失败率。sleep(1) 控制每个 VU 的迭代间隔,用来模拟真实用户的操作停顿;不加 sleep,单 VU 会以最快速度循环请求。两者的区别要分清:thresholds 决定测试整体成败,check 是过程性的断言记录。

运行位置

同一份脚本可以在 CLI 本地跑、在 CI 里跑,也可以跨 Kubernetes 集群分发执行。

scenarios:工作量怎么建模

stages 只是负载模型的一种简写。更细的建模能力在 Scenarios 文档(链接见文末)里,支持的方式包括开放模型(open model)、封闭模型(closed model)、恒定 RPS、固定迭代次数(fixed iterations)等。

选哪种取决于你要回答的问题:恒定 RPS 适合验证服务端在固定吞吐下的稳定性,闭合模型(固定 VU 数)更接近“用户数量固定”的真实场景,固定迭代次数适合跑确定性负载或批处理式验证。多个 scenario 可以在同一个测试里并行组合。

结果输出

k6 支持两种粒度的处理方式:输出汇总统计(summary statistics),或者把细粒度指标导出到自选后端。前者足以支撑 CI 里的通过/失败判定,后者用于事后分析、对比历史基线、接 Grafana 之类的可视化。可用的输出方式和过滤器见 Results output 文档(链接见文末)。

协议支持

内置支持 HTTP、WebSockets、gRPC、Browser 等,覆盖面还在扩展。这意味着同一套脚本框架可以同时压 API、长连接和浏览器端交互,不必为不同协议换工具。

扩展生态与 k6 Studio

内置能力覆盖不到的场景,可以通过扩展补上新的协议和用例,扩展列表见 Extensions 文档(链接见文末)。

不想写代码的场景,可以用 k6 Studio(github.com/grafana/k6-studio):这是一个桌面应用,通过录制或配置生成 k6 脚本,生成的产物仍是标准 k6 脚本,可以直接拿去跑或改。

链接汇总

许可证为 AGPL-3.0。

上手时注意一点:默认示例脚本里的地址是公开的演示站点,换成本地或预发环境前,先确认目标服务能承受对应量级的并发。

复制全文 生成海报 性能测试 压测 k6 负载测试 CI

推荐文章

程序员茄子在线接单