3. k6 基础架构:核心概念与运行原理

k6 采用 单进程、多协程(Go 语言 goroutine) 的架构,将每个虚拟用户(VU)抽象为一个轻量级 goroutine,而非操作系统线程。这种设计使得 k6 能够在单机节点上轻松模拟数万并发用户,同时保持极低的内存开销。理解 k6 的四个核心概念——VU、场景、指标、检查点——是掌握 k6 脚本编排与压测执行的基础。

核心认知: k6 的架构哲学是“脚本即配置”。VU、场景、指标、检查点均在 JavaScript 脚本中声明,无需外部配置文件,这与 JMeter 的 GUI 配置方式形成鲜明对比。

3.1 核心概念详解

3.1.1 VU(虚拟用户)

VU 是 k6 中执行压测请求的最小单元。每个 VU 独立运行一份 JavaScript 脚本副本,拥有独立的上下文(包括全局变量、模块缓存)。VU 的生命周期由 k6 运行时管理,开发者通过 export default function 定义 VU 的主执行逻辑。

属性 说明 典型值
并发数 同时运行的 VU 数量 10 ~ 10,000+
迭代次数 每个 VU 执行 default 函数的次数 1 ~ 无限(配合 duration)
内存占用 每个 VU 约 1~2 MB(含 JS 运行时) 10,000 VU ≈ 10~20 GB
启动方式 由场景(Scenario)调度器按配置逐步或瞬时启动 ramp-up / pause / target
// 示例:VU 主函数定义
import http from 'k6/http';
import { sleep } from 'k6';

export default function () {
  // 每个 VU 独立执行此函数
  http.get('https://test.k6.io');
  sleep(1);
}

3.1.2 场景(Scenario)

场景是 k6 中定义 VU 行为模式的顶层配置单元。一个压测脚本可以包含多个场景,每个场景独立控制 VU 数量、执行时长、迭代次数和流量模型。k6 内置三种执行器(Executor),覆盖常见的压测模式。

执行器类型 适用场景 关键参数
shared-iterations 固定总迭代次数,VU 共享 vus, iterations
per-vu-iterations 每个 VU 执行固定迭代次数 vus, iterations
constant-vus 恒定并发,持续时长 vus, duration
ramping-vus 阶梯式增减并发 stages: [{target, duration}]
externally-controlled 由外部控制器(如 k6-operator)动态调整 vus, duration, maxVUs
// 示例:多场景配置
export const options = {
  scenarios: {
    smoke_test: {
      executor: 'constant-vus',
      vus: 1,
      duration: '30s',
    },
    load_test: {
      executor: 'ramping-vus',
      stages: [
        { duration: '2m', target: 100 },  // 爬坡
        { duration: '5m', target: 100 },  // 稳定
        { duration: '2m', target: 0 },    // 下降
      ],
    },
  },
};

3.1.3 指标(Metrics)

k6 内置四种指标类型,用于收集压测过程中的性能数据。所有指标默认输出到终端、JSON 文件和内置的 Web Dashboard(k6 新版本)。

指标类型 内置指标示例 说明
Counter http_reqs, iterations, data_received 累计计数,可计算速率
Gauge vus, vus_max 当前瞬时值
Rate checks, failed checks 通过/失败比率
Trend http_req_duration, http_req_waiting 统计分布(min/max/avg/p(90)/p(95))
// 示例:自定义指标
import { Trend, Rate, Counter } from 'k6/metrics';

const myTrend = new Trend('api_response_time');
const myRate = new Rate('success_rate');
const myCounter = new Counter('total_orders');

export default function () {
  const res = http.get('https://api.example.com/orders');
  myTrend.add(res.timings.duration);
  myRate.add(res.status === 200);
  myCounter.add(1);
}

3.1.4 检查点(Checks)

检查点是 k6 中内置的断言机制,用于验证 HTTP 响应是否符合预期。检查点失败不会终止脚本执行,但会记录失败次数并影响 checks 和 failed checks 指标。

// 示例:检查点用法
import { check } from 'k6';
import http from 'k6/http';

export default function () {
  const res = http.get('https://test.k6.io');
  
  check(res, {
    'status is 200': (r) => r.status === 200,
    'response body contains welcome': (r) => r.body.includes('Welcome'),
    'response time < 500ms': (r) => r.timings.duration < 500,
  });
}
注意: 检查点与 JMeter 的断言(Assertion)功能类似,但 k6 的检查点默认不会中断请求流程。如需在检查点失败时停止 VU 或场景,需结合 thresholds(阈值)或自定义逻辑实现。

3.2 运行原理:事件循环与调度

k6 的运行基于 Go 语言的 事件循环(Event Loop) 和 goroutine 调度器。每个 VU 对应一个 goroutine,k6 运行时通过 场景调度器(Scenario Scheduler) 控制 VU 的创建、执行和销毁。

k6 运行原理架构图 k6 运行原理架构图 k6 CLI / 脚本入口 场景调度器(Scenario Scheduler) VU 池(goroutine 池) VU #1 VU #2 VU #3 VU #4 VU #5 VU #N 事件循环(Event Loop) 异步 I/O · HTTP 请求 · 定时器 · 检查点 指标收集 · 阈值评估 · 结果输出

3.3 运行流程详解

  1. 脚本解析与初始化: k6 读取 JavaScript 脚本,解析 options 配置(场景、阈值、指标),初始化全局模块。
  2. VU 创建与启动: 场景调度器根据配置的 executor 和 vus 参数,创建对应数量的 goroutine(VU)。每个 VU 加载脚本副本,进入就绪状态。
  3. 迭代执行: 每个 VU 在事件循环中反复执行 export default function,直到达到迭代次数或场景时长限制。每次迭代包含:发送 HTTP 请求、执行检查点、记录自定义指标、调用 sleep() 等。
  4. 指标收集与阈值评估: 所有内置和自定义指标实时汇总到 k6 的指标引擎。在每个时间窗口结束时,k6 评估 thresholds 配置,判断是否触发 abortOnFail 或输出告警。
  5. 结果输出: 压测结束后,k6 将指标数据输出到终端摘要、JSON 文件、CSV 文件或外部存储(如 InfluxDB、Prometheus)。
关键洞察: k6 的“单进程多协程”架构使其在同等硬件资源下,能够支持的并发 VU 数量远超 JMeter(JMeter 每个 VU 对应一个 Java 线程)。在 8 核 16GB 的服务器上,k6 通常可稳定运行 30,000+ VU,而 JMeter 的极限约为 5,000~10,000 线程。

3.4 核心概念关系图

以下 SVG 图展示了 VU、场景、指标、检查点之间的协作关系,以及它们如何共同构成一次完整的压测执行。

k6 核心概念关系图 k6 核心概念关系图 场景(Scenario) VU(虚拟用户) goroutine · 独立上下文 指标(Metrics) Counter/Gauge/Rate/Trend 检查点(Checks) 断言 · 不中断执行 阈值(Thresholds) 通过/失败条件 调度 配置 执行 评估 结果记录

3.5 与 JMeter 架构对比

对比维度 k6 JMeter
并发模型 单进程多协程(goroutine) 多线程(每个 VU 一个 Java 线程)
资源开销 低(10,000 VU ≈ 10~20 GB) 高(10,000 VU ≈ 30~50 GB)
脚本语言 JavaScript(ES6+) XML(GUI 配置) + Groovy/Java
场景定义 代码内声明(options.scenarios) GUI 线程组配置
指标收集 内置 4 种类型 + 自定义 监听器 + 聚合报告
检查点/断言 check() 函数,不中断执行 断言元件,可中断线程
分布式执行 k6-operator(Kubernetes) Master-Slave 模式
选型建议: 如果团队偏向代码化、CI/CD 集成、云原生环境,k6 是更优选择;如果团队习惯 GUI 操作、需要丰富的第三方插件生态,JMeter 仍然适用。两者可以互补使用——k6 用于高频回归和巡检,JMeter 用于复杂业务逻辑模拟。