k6 负载测试工具:脚本化性能测试

FreeGuideOnline 最新 2026-06-16

k6 负载测试工具:脚本化性能测试完全指南

目录

  1. 什么是 k6 以及为什么选择它
  2. 环境准备与安装
  3. 编写你的第一个测试脚本
  4. k6 的核心概念
  5. 高级脚本设计模式
  6. 结果分析与可视化
  7. 分布式测试与云集成
  8. 常见问题与调试技巧
  9. 下一步学习资源

什么是 k6 以及为什么选择它

k6 是一款现代的开源负载测试工具,专为开发者和 DevOps 团队设计。它使用 Go 语言编写引擎,但允许你通过 JavaScript(ES6) 编写测试脚本。这使得测试即代码(TaaC)的理念得以贯彻,性能测试可以像应用程序代码一样被版本控制、代码审查以及集成到 CI/CD 流水线中。

与传统工具的区别

  • 脚本化优先:告别繁琐的 XML 配置,用你熟悉的 JavaScript 表达复杂的测试逻辑。
  • 高性能低资源消耗:基于 Go 的高效 goroutine 调度,单个实例即可生成海量并发。
  • 开发友好:内置 CLI、丰富的执行器(Executors)以及一键输出到多种后端(InfluxDB、Cloud、Prometheus 等)。
  • 原生云原生:易于容器化,支持在 Kubernetes 中作为 Job 运行,也提供官方云服务 k6 Cloud。

如果你需要验证 API 在高流量下的表现、模拟用户峰值访问,或持续监控服务端性能,k6 是目前最流畅的解决方案之一。


环境准备与安装

本地安装

根据不同操作系统选择:

macOS

brew install k6

Windows
使用 Chocolatey:

choco install k6

或从 GitHub Releases 下载 .msi 安装包。

Linux (Debian/Ubuntu)

sudo apt-get update
sudo apt-get install k6

其他发行版请参考官方文档。

Docker 方式运行

docker pull grafana/k6
docker run --rm -i grafana/k6 run - <script.js

安装完成后,验证:

k6 version

应显示类似 k6 v0.49.0 的版本信息。

项目结构建议

为保持可维护性,推荐以下目录布局:

my-load-tests/
├── scripts/           # 测试脚本
│   ├── smoke.js       # 冒烟测试
│   ├── load.js        # 负载测试
│   └── stress.js      # 压力测试
├── helpers/           # 可复用模块
│   └── http.js        # 封装请求函数
├── data/              # 测试数据 (JSON/CSV)
└── results/           # 输出结果

编写你的第一个测试脚本

k6 脚本必须至少包含一个默认导出的函数,该函数将作为每个虚拟用户的入口点。

创建一个文件 api-test.js

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

export const options = {
  vus: 10,         // 同时运行的虚拟用户数
  duration: '30s', // 测试持续时间
};

export default function () {
  const res = http.get('https://test-api.example.com/users');
  
  // 断言状态码与响应时间
  check(res, {
    'status is 200': (r) => r.status === 200,
    'response time < 500ms': (r) => r.timings.duration < 500,
  });

  sleep(1); // 用户等待时间,模拟真实行为
}

在终端执行:

k6 run api-test.js

你将看到实时终端输出,包括虚拟用户数、请求速率、失败率以及标准检查点结果。测试结束后会打印包含百分位响应时间的摘要表格。


k6 的核心概念

虚拟用户与迭代

虚拟用户 (VUs) 是独立运行的并发执行单元。每个 VU 会不断循环调用 default 函数,一次执行称为一次迭代
你可以通过 options 控制并发模式:

export const options = {
  vus: 50,   // 固定并发用户数
  iterations: 1000, // 指定所有 VU 总共完成的迭代次数
};

若同时设置 durationiterations,测试会在哪个条件先达到时停止。

生命周期

k6 脚本有四个生命周期阶段:

  1. init 阶段:加载导入的模块、读取文件、定义配置。此阶段每个 VU 共享一个 JavaScript 上下文,适合初始化全局数据。
  2. setup 阶段:在执行测试逻辑前运行一次,常用于获取认证令牌或数据预热。
  3. VU 阶段 (default 函数):每个 VU 独立执行的测试代码,是主要的性能测试负载。
  4. teardown 阶段:所有 VU 结束后运行一次,用于清理资源。

示例:

export function setup() {
  // 获取 token
  const res = http.post('https://auth.example.com/token', { login: 'user' });
  return { token: res.json('token') };
}

export default function (data) {
  // 使用从 setup 传递的数据
  console.log(`My token: ${data.token}`);
  // ... 请求逻辑
}

export function teardown(data) {
  // 注销或清理
}

阈值与检查点

  • Check(检查点):用于断言单个请求的正确性,但不停止测试。结果会统计到最终报告中。
  • Thresholds(阈值):定义通过/失败标准,当指标超过设定值时测试会被标记为失败。
export const options = {
  thresholds: {
    http_req_failed: ['rate<0.01'],   // 失败率必须低于1%
    http_req_duration: ['p(95)<200'], // 95%请求响应时间低于200ms
  },
};

阈值的表达式形式为 聚合函数(参数) <条件> <值>,例如 p(95)<500 表示第95百分位数要小于500毫秒。


高级脚本设计模式

数据驱动测试

对于需要参数化输入的场景,可使用 SharedArrayopen 函数读取 CSV/JSON 文件。

读取 JSON 数据

import { SharedArray } from 'k6/data';

const users = new SharedArray('users', function () {
  return JSON.parse(open('./data/users.json'));
});

export default function () {
  const randomUser = users[Math.floor(Math.random() * users.length)];
  const payload = JSON.stringify(randomUser);
  http.post('https://httpbin.org/post', payload);
}

SharedArray 确保数据只加载一次并共享给所有 VU,内存友好。

动态生成测试数据
利用 k6/crypto 和内置的随机函数:

import { randomIntBetween, randomString } from 'https://jslib.k6.io/k6-utils/1.2.0/index.js';

export default function () {
  const randomEmail = `user_${randomString(8)}@test.com`;
  // ...
}

场景与执行器

k6 通过场景 (scenarios) 实现复杂的测试调度。每个场景可以指定独立的执行器和并发模型。

export const options = {
  scenarios: {
    // 场景1:逐步增加负载
    ramping_load: {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '2m', target: 100 }, // 爬升至100 VU
        { duration: '5m', target: 100 }, // 保持100 VU
        { duration: '2m', target: 0 },   // 降至0
      ],
      gracefulRampDown: '30s',
    },
    // 场景2:恒定高速请求,不关心VU数量
    constant_request_rate: {
      executor: 'constant-arrival-rate',
      rate: 500,              // 每秒迭代次数
      timeUnit: '1s',
      duration: '5m',
      preAllocatedVUs: 50,
      maxVUs: 200,
    },
  },
};

常用执行器:

  • ramping-vus:适合模拟流量高峰。
  • constant-arrival-rate:精确控制每秒请求数,推荐用于 API 压测。
  • per-vu-iterations:每个 VU 执行固定次数迭代。

自定义指标与标签

你可以创建自定义指标收集业务维度的数据:

import { Trend, Counter, Gauge, Rate } from 'k6/metrics';

const waitTime = new Trend('wait_time', true); // true 表示包含在摘要中
const itemsProcessed = new Counter('items_processed');
const activeConnections = new Gauge('active_connections');

export default function () {
  const start = Date.now();
  // ... some operation
  waitTime.add(Date.now() - start);
  
  itemsProcessed.add(1);
  activeConnections.add(1);
}

标签 (Tags) 允许按维度拆分数据:

http.get('https://api.example.com', {
  tags: { endpoint: 'list-users', version: 'v1' },
});

之后在结果输出中可按 endpoint 分组查看统计。


结果分析与可视化

内置输出方式

k6 在运行结束后默认输出控制台摘要,也支持通过 --out 将实时指标流式发送到外部后端:

  • InfluxDB + Grafana:经典的监控栈。
    k6 run --out influxdb=http://localhost:8086/k6 script.js
    
  • Prometheus Remote Write:适合云端原生环境。
  • CSVk6 run --out csv=results.csv script.js 便于离线分析。
  • k6 Cloud:官方 SaaS 服务,提供美观的图形化仪表盘和协作功能。
    k6 login cloud --token <your-token>
    k6 run --out cloud script.js
    

在脚本中生成 HTML 报告

使用社区扩展 K6 HTML Report

npm install -g k6-reporter
k6 run --out json=results.json script.js
k6-reporter results.json

将生成一个独立的 HTML 文件,包含图表和表格。

关键指标解读

运行结束后重点关注:

  • http_req_duration:平均、中位数、p95、p99 响应时间。
  • http_req_failed:失败率,通常与阈值结合判断健康状态。
  • iterations:总迭代次数,反映测试吞吐。
  • vusvus_max:实际并发及最大并发。

分布式测试与云集成

对于需要超大规模负载的场景(如百万并发),单台机器可能成为瓶颈。k6 提供两种扩展路径:

使用 k6-operator (Kubernetes)

利用 Grafana k6-operator 在 Kubernetes 集群中运行分布式测试。它通过自定义资源 K6 将测试脚本分发到多个 Pod 并行执行,并自动聚合结果。

示例定义:

apiVersion: k6.io/v1alpha1
kind: K6
metadata:
  name: my-distributed-test
spec:
  parallelism: 10   # 10个并行执行器
  script:
    configMap:
      name: my-test-script
      file: test.js

每个执行器独立运行一段负载,最终将指标汇总。

k6 Cloud 上的分布式测试

在脚本中设置 options.cloud 或直接通过 CLI 参数启用云执行:

k6 cloud script.js

云服务自动调度多个负载生成区域,最大支持数百万 VU。

决策:若团队已有 K8s 基础设施,推荐使用 operator 保持控制权;若追求极简与快速扩展,k6 Cloud 是理想选择。


常见问题与调试技巧

1. “http_req_duration” 指标比实际感觉慢

  • 检查是否包含了 DNS 解析和 TCP 连接时间。可使用 http_req_connectinghttp_req_blocked 等细分指标定位。
  • 确认客户端网络是否有限制,或在同一机器上运行太多 VU 导致 CPU 饱和。

2. 脚本中使用了第三方 npm 包

k6 不是 Node.js,不支持完整 Node API。需要使用纯 JavaScript 库或官方 JSLib。将通过 webpack/rollup 打包的脚本导入 k6 是常用方案。

打包示例 (webpack):

npm init -y
npm install webpack webpack-cli

将脚本打包为单文件:

// webpack.config.js
module.exports = {
  entry: './src/test.js',
  output: { filename: 'bundle.js', path: __dirname },
  mode: 'production',
  target: 'web', // 注意,不是 node
};

然后 k6 run bundle.js

3. 如何调试脚本

  • 使用 --http-debug 打印所有请求响应的详细信息:
    k6 run --http-debug="full" script.js
    
  • 在脚本中添加 console.log 查看变量状态。
  • 利用 --no-usage-report 禁止发送匿名统计,清理输出。

4. 测试未达到设定的 VU 数量

可能受限于 --compatibility-mode 或系统文件描述符限制。检查 ulimit:

ulimit -n 100000

确保机器资源充足。


下一步学习资源

学习性能测试不仅仅是掌握工具,以下是官方和社区推荐:

  • 官方文档k6.io/docs – 最权威的命令参考和指南。
  • k6 示例库GitHub k6-community/examples 包含多种场景。
  • 《k6 学院》视频k6.io/academy 免费交互式课程。
  • Grafana 负载测试博客:定期发布最佳实践。
  • 参与社区:GitHub Discussions 与 Slack 频道 #k6,遇到问题积极提问。

开始你的脚本化性能测试之旅吧!试着对公司的 API 或一个公开接口编写负载测试脚本,并用阈值定义你的服务等级目标(SLO)。每一次按 Enter 运行,都是在为系统的可靠性增加一道防线。