跳转到内容

k6 — 用 JS 写脚本的现代负载测试器

是什么

k6 是 Grafana Labs 开源的负载测试工具——你写一段 JavaScript,告诉它”模拟 1000 个用户,每秒访问我的 API 一次,跑 5 分钟”,它就替你打过去,最后给你一份报告:平均响应时间多少、有多少请求失败、99 分位延迟多少。

日常类比:像压力测试用的健身教练——你说”我要练 30 分钟、心率拉到 150”,它就盯着秒表和心率带,结束后告诉你”第 12 分钟你掉链子了,那一刻有 3% 动作失败”。

// 一份最小 k6 脚本
import http from 'k6/http';
import { check } from 'k6/check';
export const options = {
vus: 100, // 100 个虚拟用户
duration: '30s', // 跑 30 秒
};
export default function () {
const res = http.get('https://example.com/api/health');
check(res, { 'status is 200': (r) => r.status === 200 });
}

k6 run script.js,30 秒后给你打印出 RPS、p95、错误率。没有 GUI、没有配置文件、没有 XML

为什么重要

  • CI 原生:单二进制(Go 写的),一条 docker run grafana/k6 run script.js 就跑——GitHub Actions、GitLab CI 里加一行就能在每次合并前自动压一遍
  • 脚本是代码:不是 jmeter 那种 GUI 拖拽然后存成 XML,是真正的 JS 文件,能进 Git、能 review、能 import 共享逻辑
  • 指标接 Grafana 全家桶:原生输出 Prometheus / InfluxDB / OpenTelemetry,跑完直接在 grafana 看板里看
  • GitHub 26k stars:Locust(Python)/ Artillery(Node)的同代竞品里,k6 的 CI 体验和指标生态最好
  • 被 Grafana 收购:2021 年 LoadImpact 公司被 Grafana 买下,从此 k6 是 Grafana 可观测性栈的”主动生成数据那一端”——和 prometheus / Loki / Tempo 拼成完整闭环

核心要点

k6 的世界由 5 个概念搭起来:

  1. VU(Virtual User,虚拟用户):一个并发执行单元,可以理解成”一个假装在用你 App 的人”。100 VU 就是 100 个并发会话。

  2. Iteration(迭代):每个 VU 一遍遍执行 default 导出的函数,每跑一遍叫一次 iteration。VU 跑完一次迭代立刻接下一次,直到时间到。

  3. Scenario(场景):组织 VU 的高级方式。比如”前 30 秒慢慢从 0 爬到 100 VU,再保持 2 分钟”——这叫 ramping-vus scenario。一个测试可以并行跑多个 scenario(“100 个用户在浏览 + 同时 10 个用户在下单”)。

  4. Check:软断言(assert)。check(res, { 'status 200': r => r.status === 200 }) 失败了不会让测试停,但会在报告里记一笔失败率。

  5. Threshold(阈值):硬断言。thresholds: { http_req_duration: ['p(95)<500'] } 意思是”95 分位响应时间必须小于 500ms”,超过就让 k6 run 退出码非 0——CI 看到失败就把构建标红。

引擎细节:k6 内部用 goja(一个纯 Go 写的 JavaScript 运行时)跑你的脚本——不开 Node 进程,所以单二进制就能跑、内存占用也低。代价是它不支持 Node 的 npm 生态,需要的库要么 webpack 打包进来,要么用 xk6 扩展。

实践案例

案例 1:阶梯加压,看你的 API 在多少 RPS 时崩

export const options = {
scenarios: {
ramp_up: {
executor: 'ramping-vus',
stages: [
{ duration: '30s', target: 50 }, // 30 秒爬到 50 VU
{ duration: '1m', target: 200 }, // 1 分钟爬到 200 VU
{ duration: '30s', target: 0 }, // 30 秒降到 0
],
},
},
thresholds: {
http_req_failed: ['rate<0.01'], // 错误率 < 1%
http_req_duration: ['p(95)<800'], // p95 < 800ms
},
};

跑完 k6 会告诉你 p95 在什么并发量下突破 800ms——这就是你的容量上限。

案例 2:把指标导给 Prometheus,在 grafana 看板看

Terminal window
k6 run --out experimental-prometheus-rw=http://prom:9090/api/v1/write script.js

Prometheus 收到 k6_http_req_duration / k6_vus / k6_http_reqs 等指标,进 grafana 选官方 dashboard 19665,立刻有图:响应时间曲线、并发数、错误率。

案例 3:CI 里跑,超阈值自动让构建失败

.github/workflows/load.yml
- name: k6 load test
uses: grafana/k6-action@v0.3.1
with:
filename: tests/checkout.js

k6 的 threshold 没达标 → 进程退出码 1 → GitHub Actions 标红 → PR 不能合。这就是”性能回归门禁”。

踩过的坑

  1. k6 不是 Node:不能直接 import lodash 用 npm 包。要么 webpack 打包,要么换成 k6 自带的 k6/encodingk6/crypto 这些原生模块。第一次写脚本最容易踩。

  2. VU 不等于真实用户:VU 是并发执行体,没有思考时间——它跑完一次迭代立刻发下一次请求。要模拟真实用户得自己加 sleep(Math.random() * 5)

  3. 本地跑 1 万 VU 不现实:单机 k6 大约能撑 1k–2k VU(看脚本复杂度)。再高得用 k6-operator 在 K8s 里分布式跑,或者花钱用 Grafana Cloud k6。

  4. threshold 写错不报错thresholds: { http_req_duration: ['p95<500'] } 这里 p95 应该是 p(95)——少了括号,k6 会忽略这条 threshold,CI 假绿。

  5. xk6 扩展每次重 build:想用 xk6-browser(浏览器自动化)就得本地跑 xk6 build --with github.com/grafana/xk6-browser,得到一个新的 k6 二进制——官方镜像里没有,需要自己打镜像。

适用 vs 不适用场景

适用

  • HTTP / gRPC / WebSocket API 的负载与压力测试
  • CI 里的”性能回归门禁”——每次 PR 自动跑、超阈值就拦
  • 要把性能指标进可观测性栈(Prometheus / grafana / Tempo)的团队
  • 工程师为主的团队——大家都会写 JS

不适用

  • 浏览器端真实用户体验测试(那是 playwright / Lighthouse 的活,k6 的 xk6-browser 是补丁不是主业)
  • 测试人员主导、不写代码的团队(GUI 用户更适合 jmeter
  • 复杂业务逻辑用 Python 写顺手的团队 → 看 Locust
  • 单机要求 >5k VU 的极端压测 → k6 单机吃力,得分布式

历史小故事(可跳过)

  • 2016:瑞典 LoadImpact 公司把内部测试工具开源,命名 k6(“K6 是世界第二高峰乔戈里峰的代号”——压力测试嘛)
  • 2017:1.0 发布,定位”开发者友好的负载测试器”
  • 2021:Grafana Labs 收购 LoadImpact,k6 进入 Grafana 可观测性家族
  • 2022–2024:xk6 扩展生态爆发——browser、sql、kafka、redis 全有了
  • 2025:在负载测试工具调查里 k6 成为开源类第一,超过 jmeter

学到什么

  1. 测试即代码:性能测试也该像单元测试一样进 Git、进 CI、被 review,不是某个测试工程师电脑里的 jmx 文件
  2. threshold 是 CI 友好的关键:硬断言 + 退出码 → 构建系统能直接判断通过失败,不需要人去看图
  3. 单二进制 + 嵌入式 JS 的组合很聪明:Go 给你性能和易部署,JS 给你脚本表达力,goja 把两边粘起来
  4. 可观测性闭环:被测系统在出指标,测试工具也在出指标,两边进同一个 grafana 看板对照——这是 Grafana 收购 k6 后画的大图

延伸阅读

  • 官方文档:k6.io/docs(写得清楚,按场景查)
  • 入门教程:Grafana k6 quickstart(10 分钟从 0 跑起来)
  • 进阶 scenario:k6 scenarios doc(搞懂 ramping-vus / constant-arrival-rate 这些 executor)
  • xk6 扩展:xk6 仓库(写自己的 Go 模块)
  • jmeter —— 老牌 GUI 负载测试器,对比着看更清楚 k6 设计哲学
  • locust —— Python 同代竞品

关联

  • grafana —— k6 的母公司,指标天然进 Grafana 看板
  • prometheus —— k6 原生导出 Prometheus 指标
  • playwright —— 浏览器测试,和 k6 互补(一个测体验、一个测吞吐)
  • jmeter —— 上一代负载测试事实标准,k6 的对比对象
  • locust —— Python 写脚本的同代竞品

反向链接

  • grafana —— Grafana — 监控可视化看板
  • locust —— Locust — 用 Python 写压测脚本的分布式负载工具
  • playwright —— Playwright — 跨浏览器自动化测试
  • prometheus —— Prometheus — 时序监控系统