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 个概念搭起来:
-
VU(Virtual User,虚拟用户):一个并发执行单元,可以理解成”一个假装在用你 App 的人”。100 VU 就是 100 个并发会话。
-
Iteration(迭代):每个 VU 一遍遍执行
default导出的函数,每跑一遍叫一次 iteration。VU 跑完一次迭代立刻接下一次,直到时间到。 -
Scenario(场景):组织 VU 的高级方式。比如”前 30 秒慢慢从 0 爬到 100 VU,再保持 2 分钟”——这叫
ramping-vusscenario。一个测试可以并行跑多个 scenario(“100 个用户在浏览 + 同时 10 个用户在下单”)。 -
Check:软断言(assert)。
check(res, { 'status 200': r => r.status === 200 })失败了不会让测试停,但会在报告里记一笔失败率。 -
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 看板看
k6 run --out experimental-prometheus-rw=http://prom:9090/api/v1/write script.jsPrometheus 收到 k6_http_req_duration / k6_vus / k6_http_reqs 等指标,进 grafana 选官方 dashboard 19665,立刻有图:响应时间曲线、并发数、错误率。
案例 3:CI 里跑,超阈值自动让构建失败
- name: k6 load test uses: grafana/k6-action@v0.3.1 with: filename: tests/checkout.jsk6 的 threshold 没达标 → 进程退出码 1 → GitHub Actions 标红 → PR 不能合。这就是”性能回归门禁”。
踩过的坑
-
k6 不是 Node:不能直接
import lodash用 npm 包。要么 webpack 打包,要么换成 k6 自带的k6/encoding、k6/crypto这些原生模块。第一次写脚本最容易踩。 -
VU 不等于真实用户:VU 是并发执行体,没有思考时间——它跑完一次迭代立刻发下一次请求。要模拟真实用户得自己加
sleep(Math.random() * 5)。 -
本地跑 1 万 VU 不现实:单机 k6 大约能撑 1k–2k VU(看脚本复杂度)。再高得用 k6-operator 在 K8s 里分布式跑,或者花钱用 Grafana Cloud k6。
-
threshold 写错不报错:
thresholds: { http_req_duration: ['p95<500'] }这里p95应该是p(95)——少了括号,k6 会忽略这条 threshold,CI 假绿。 -
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
学到什么
- 测试即代码:性能测试也该像单元测试一样进 Git、进 CI、被 review,不是某个测试工程师电脑里的 jmx 文件
- threshold 是 CI 友好的关键:硬断言 + 退出码 → 构建系统能直接判断通过失败,不需要人去看图
- 单二进制 + 嵌入式 JS 的组合很聪明:Go 给你性能和易部署,JS 给你脚本表达力,goja 把两边粘起来
- 可观测性闭环:被测系统在出指标,测试工具也在出指标,两边进同一个 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 — 时序监控系统