4. k6 脚本核心语法(二):参数化、环境变量与场景配置

在上一节掌握了基础请求与检查点之后,本节将深入 k6 脚本的四个关键进阶能力:参数化(使用内置变量 __VU 与 __ITER)、环境变量管理、场景(Scenario)配置,以及 ramping-arrival-rate 执行器的实战用法。这些能力是构建真实、可复用、高仿真压测脚本的基石。

4.1 参数化:使用 __VU 与 __ITER

在分布式压测中,每个虚拟用户(VU)的行为需要具备一定的差异性,避免所有 VU 在同一时刻执行完全相同的操作(即“惊群效应”)。k6 提供了两个内置变量来实现轻量级参数化:

变量 类型 含义 典型用途
__VU 整数 当前虚拟用户的唯一编号(从 1 开始) 按用户 ID 分配数据分片、模拟不同用户登录
__ITER 整数 当前 VU 已执行的迭代次数(从 0 开始) 控制循环进度、按迭代轮次切换测试数据
关键区别: __VU 在 VU 生命周期内保持不变;__ITER 随每次迭代递增。两者组合可生成全局唯一的请求标识。

以下示例展示了如何利用 __VU 和 __ITER 构造动态请求体:

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

export default function () {
  // 使用 __VU 和 __ITER 构造唯一的用户标识
  const userId = `user_${__VU}_iter_${__ITER}`;
  const payload = JSON.stringify({
    username: userId,
    action: 'search',
    timestamp: Date.now()
  });

  const params = {
    headers: { 'Content-Type': 'application/json' },
  };

  const res = http.post('http://test.k6.io/api/search', payload, params);

  check(res, {
    'status is 200': (r) => r.status === 200,
    'response has data': (r) => r.body.length > 0,
  });

  sleep(1);
}
最佳实践: 当压测目标需要模拟大量不同用户时,优先使用 __VU 作为用户 ID 的种子,避免所有 VU 使用相同的测试账号导致服务端限流或数据冲突。

4.2 环境变量:灵活配置压测参数

环境变量允许你在不修改脚本代码的前提下,动态调整压测目标地址、阈值、数据文件路径等参数。k6 支持通过 __ENV 对象读取环境变量,并在命令行中使用 -e 标志注入。

脚本中读取环境变量:

import http from 'k6/http';

// 从环境变量读取目标 URL,若未设置则使用默认值
const BASE_URL = __ENV.TARGET_URL || 'http://default.test.k6.io';
const  = __ENV. || 'dev-key';

export default function () {
  const res = http.get(`${BASE_URL}/api/status`, {
    headers: { 'Authorization': `Bearer ${}` },
  });
  console.log(`VU ${__VU} - Status: ${res.status}`);
}

命令行注入环境变量:

k6 run -e TARGET_URL=http://staging.example.com -e =prod-secret-123 script.js
场景 推荐使用环境变量 示例值
多环境切换 TARGET_URL http://dev-api.example.com
密钥管理 / AUTH_ sk-xxxx
数据文件路径 DATA_FILE ./test-data/users.csv
压测持续时间 TEST_DURATION 5m
安全提醒: 切勿将敏感信息(如数据库密码、云服务密钥)硬编码在脚本中。始终通过环境变量或外部密钥管理服务注入,并确保 .env 文件不被提交到版本控制。

4.3 场景(Scenario)配置:多策略压测

k6 的场景配置允许你在同一个脚本中定义多个独立的压测策略,每个场景可以拥有不同的执行器、VU 数量、持续时间以及标签。这使得你可以同时模拟“平稳负载”和“突发流量”两种模式。

场景配置的核心结构:

import http from 'k6/http';

export const options = {
  scenarios: {
    // 场景一:恒定负载
    constant_load: {
      executor: 'constant-vus',
      vus: 10,
      duration: '30s',
      tags: { scenario_type: 'constant' },
    },
    // 场景二:突发流量
    burst_traffic: {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '10s', target: 50 },
        { duration: '20s', target: 50 },
        { duration: '10s', target: 0 },
      ],
      tags: { scenario_type: 'burst' },
      startTime: '10s', // 延迟 10 秒启动
    },
  },
};

export default function () {
  http.get('http://test.k6.io');
}
场景标签(tags) 是区分不同场景流量的关键。在结果分析时,你可以按 scenario_type 过滤指标,精确评估每种负载模式对系统的影响。

下表列出了 k6 支持的常用执行器及其适用场景:

执行器名称 行为描述 典型使用场景
constant-vus 固定数量的 VU 持续运行 基准测试、持续负载验证
ramping-vus VU 数量按阶段递增/递减 容量测试、弹性伸缩测试
constant-arrival-rate 固定速率发起迭代(忽略 VU 数量) 吞吐量测试、API 限流验证
ramping-arrival-rate 迭代速率按阶段递增/递减 尖峰流量模拟、压力爬坡测试
externally-controlled 通过 k6 API 动态控制 VU 数量 自动化测试平台集成、实时调控

4.4 ramping-arrival-rate 执行器详解

ramping-arrival-rate 是 k6 中最强大的执行器之一,它控制的是每秒发起的迭代次数(即吞吐量),而不是 VU 的数量。这意味着 k6 会自动管理 VU 池,确保达到目标速率,非常适合模拟真实世界中随时间变化的用户请求量。

核心配置参数:

export const options = {
  scenarios: {
    traffic_spike: {
      executor: 'ramping-arrival-rate',
      startRate: 10,          // 起始每秒 10 次迭代
      timeUnit: '1s',         // 速率的时间单位
      preAllocatedVUs: 20,    // 预分配的 VU 数量
      maxVUs: 100,            // 最大 VU 数量(弹性扩展上限)
      stages: [
        { duration: '30s', target: 10 },   // 保持 10 rps
        { duration: '30s', target: 50 },   // 爬坡到 50 rps
        { duration: '60s', target: 50 },   // 维持高负载
        { duration: '30s', target: 0 },    // 降为零
      ],
    },
  },
};
预分配 VU(preAllocatedVUs) 与 最大 VU(maxVUs) 的区别:预分配 VU 在场景启动时即创建,减少冷启动开销;最大 VU 是 k6 可以动态创建的上限,用于应对速率突增。建议将 preAllocatedVUs 设置为目标速率所需 VU 的 1.5~2 倍。

下面的 SVG 图展示了 ramping-arrival-rate 执行器在三个阶段中,速率与 VU 数量的动态变化关系:

ramping-arrival-rate 执行器:速率与 VU 动态变化 时间 (s) 速率 / VU 数量 阶段 1: 10 rps VU: 20 阶段 2: 10→50 rps VU: 20→60 阶段 3: 50 rps VU: 60→100 k6 自动管理 VU 池,确保达到目标迭代速率(rps) 预分配 VU 减少冷启动,最大 VU 提供弹性扩展能力

4.5 综合实战:参数化 + 环境变量 + 场景配置

将上述三个知识点整合到一个完整的压测脚本中,实现一个支持多环境、多场景、动态参数的搜索接口压测:

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

// 从环境变量读取配置
const BASE_URL = __ENV.TARGET_URL || 'http://test.k6.io';
const SEARCH_TERM = __ENV.SEARCH_TERM || 'k6';

export const options = {
  scenarios: {
    // 场景一:恒定搜索负载
    steady_search: {
      executor: 'constant-vus',
      vus: 5,
      duration: '1m',
      tags: { scenario: 'steady' },
    },
    // 场景二:搜索流量爬坡
    search_spike: {
      executor: 'ramping-arrival-rate',
      startRate: 5,
      timeUnit: '1s',
      preAllocatedVUs: 10,
      maxVUs: 50,
      stages: [
        { duration: '20s', target: 5 },
        { duration: '30s', target: 30 },
        { duration: '10s', target: 0 },
      ],
      tags: { scenario: 'spike' },
      startTime: '10s',
    },
  },
};

export default function () {
  // 使用 __VU 和 __ITER 构造差异化搜索请求
  const query = `${SEARCH_TERM}_vu${__VU}_iter${__ITER}`;
  const res = http.get(`${BASE_URL}/search?q=${encodeURIComponent(query)}`);

  check(res, {
    'search status is 200': (r) => r.status === 200,
    'search results exist': (r) => r.body.includes('results'),
  });

  sleep(0.5);
}
运行命令示例:
k6 run -e TARGET_URL=http://staging.example.com -e SEARCH_TERM=performance search-test.js

通过本节的学习,你已经掌握了 k6 脚本中参数化、环境变量、场景配置以及 ramping-arrival-rate 执行器的核心用法。这些技能将帮助你在后续的分布式压测实战中,构建出更加真实、灵活且可复用的压测脚本。