使用 k6 编写登录与业务场景脚本并进行性能测试及 Grafana 可视化实战

引言

在性能测试领域,JMeter 凭借其丰富的 GUI 和广泛的插件生态,长期占据着主导地位。然而,随着 DevOps 和持续交付理念的普及,脚本化、轻量级且易于集成到 CI/CD 管道的工具越来越受到青睐。k6 作为一款基于 Go 和 JavaScript 的现代负载测试工具,以其简洁的语法、出色的并发性能以及原生支持 InfluxDB、Prometheus 等监控生态,成为许多团队进行性能回归和容量评估的新选择。

JMeter 与 k6 的简要对比:

特性 JMeter k6
脚本语言 Java/XML(GUI 或 DSL) JavaScript(ES6)
学习曲线 较陡,需熟悉 GUI 组件 平缓,适合前端/后端开发人员
执行模式 多线程(依赖 JVM) 轻量级协程(Go)
资源消耗 较高 极低
CI/CD 集成 需借助命令行或 Maven 插件 原生支持,一条命令即可运行
监控集成 需插件或自定义 原生支持 InfluxDB、Prometheus、StatsD
报告与可视化 聚合报告、HTML 报告 内置 Web Dashboard、Grafana 集成

本文旨在为读者提供一套完整的 k6 实战指南,从编写登录脚本 (获取并保存认证凭证)到编写业务查询脚本 (模拟并发场景),再到将指标输出至 InfluxDB通过 Grafana 构建定制仪表板,实现测试结果的实时可视化。文章中的所有接口地址、参数、Cookie 值等均为示例占位符,不涉及任何真实数据。


一、编写登录脚本(获取凭证并保存至 CSV)

1.1 业务流程概述

目标系统的登录流程基于统一认证协议,一般需要三步交互:

  1. 发起登录请求:提交用户凭证(如手机号、密码)及加密令牌,响应中返回临时票据。

  2. 换取授权码 :携带临时票据请求授权接口,获取用于后续验票的 ticket 参数。

  3. 验票并获取最终凭证 :使用 ticket 换取完整的认证 Cookie,该 Cookie 将用于所有后续业务请求。

登录成功后,我们将两个用户的完整 Cookie 按行写入 CSV 文件,供后续业务场景复用。

1.2 核心实现思路

在 k6 中,我们利用 http 模块发送请求,并使用 response.cookies 对象自动解析 Set-Cookie 头,避免手动正则提取。主要逻辑如下:

  • 定义环境变量(如目标域名、协议)和固定加密参数(由开发提供,直接硬编码)。

  • 实现三个核心函数,分别对应上述三步,每个函数接收必要的参数(如用户名、临时票据),返回提取到的关键值。

  • default 函数中,从 CSV 数据文件中读取用户信息,依次为两个用户执行登录流程,若成功则将两个用户的 Cookie 拼接成一行记录,并通过 console.log 输出。

代码结构抽象示例:

javascript

复制代码
// 步骤1:登录获取临时票据
function step1_login(username, password) { ... return { ticketA, ticketB }; }

// 步骤2:使用临时票据换取 ticket
function step2_getTicket(ticketA, ticketB) { ... return ticket; }

// 步骤3:验票获取最终 Cookie
function step3_validate(ticket, ticketB) { ... return cookieString; }

// 主循环
export default function () {
  const user = getNextUser();
  const temp = step1_login(user.tel);
  const tic = step2_getTicket(temp.ticketA, temp.ticketB);
  const cookie = step3_validate(tic, temp.ticketB);
  console.log(`RECORD:${user.name},${user.tel},${cookie},...`);
}

实际实现中,我们利用了 k6 的 response.cookies 自动管理 Cookie,并使用了 extractAndAssembleCookies 工具函数将响应中的所有 Cookie 拼接为请求头所需的格式。

1.3 生成 CSV 文件

运行登录脚本,并通过管道提取 RECORD: 行写入文件(PowerShell 示例):

powershell

复制代码
k6 run login.js 2>&1 | Select-String 'RECORD:' | ForEach-Object { $_ -replace '.*RECORD:', '' } | Set-Content -Encoding UTF8 cookies.csv

生成的 CSV 表头为:姓名1,手机号1,cookie1,姓名2,手机号2,cookie2,单位编码,每一行包含两个用户的完整 Cookie。


二、编写业务场景脚本(模拟并发查询)

业务接口为 POST /api/your-business-endpoint,需要携带登录 Cookie。我们加载上一步生成的 CSV,构建并发测试。

2.1 加载 CSV 数据

使用 k6 内置的 open()SharedArray 手动解析(避免第三方库):

javascript

复制代码
import { SharedArray } from 'k6/data';

function parseCSV(content) {
  const lines = content.trim().split('\n');
  if (lines.length === 0) return [];
  const headers = lines[0].split(',').map(h => h.trim());
  const data = [];
  for (let i = 1; i < lines.length; i++) {
    const values = lines[i].split(',').map(v => v.trim());
    if (values.length === headers.length) {
      const row = {};
      headers.forEach((h, idx) => { row[h] = values[idx]; });
      data.push(row);
    }
  }
  return data;
}

const cookieData = new SharedArray('cookies', () => {
  const content = open('./cookies.csv');
  const rows = parseCSV(content);
  return rows.filter(row => row.cookie1 && row.cookie1.trim() !== '');
});

2.2 配置并发选项

我们设置 5 个并发虚拟用户(VU),持续 60 秒,并设定性能阈值:

javascript

复制代码
export const options = {
  vus: 5,
  duration: '60s',
  thresholds: {
    http_req_duration: ['p(95)<3000'], // 95% 请求低于 3 秒
    http_req_failed: ['rate<0.01'],    // 错误率低于 1%
  },
};

2.3 构建请求与断言

default 函数中,根据 VU 索引循环取 Cookie,构造 JSON 请求体,发送 POST 请求,并校验状态码和业务返回标志。

javascript

复制代码
function getCurrentDate() {
  const d = new Date();
  return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`;
}

export default function () {
  const idx = (__VU - 1) % cookieData.length;
  const cookie = cookieData[idx].cookie1 || '';

  const url = `https://${CONFIG.baseUrl}/api/your-business-endpoint`;
  const body = JSON.stringify({
    // 请求体结构(示例占位)
    filters: [],
    page: { pageNum: 1, pageSize: 100 },
    // 其他参数
  });

  const res = http.post(url, body, {
    headers: {
      'Content-Type': 'application/json',
      'Cookie': cookie,
      'User-Agent': 'k6-test',
    },
    tls: { insecureSkipTLSVerify: true }, // 测试环境可关闭证书校验
  });

  check(res, {
    '状态码200': (r) => r.status === 200,
    '业务成功': (r) => r.body && r.body.includes('"flag":"success"'),
  });
}

说明 :我们移除了 sleep(1),使 VU 连续发送请求,以模拟无思考时间的负载模式,从而获得更高的吞吐量。


三、执行测试并输出到 InfluxDB

k6 支持直接将指标写入 InfluxDB(v1.x),命令格式如下:

bash

复制代码
k6 run --out influxdb=http://<influxdb-ip>:8086/k6 business_test.js

执行后,控制台会实时输出测试汇总。本次 60 秒测试,5 个 VU 共完成 10650 个请求,吞吐量约 177 req/s,平均响应时间约 27.8 ms,错误率为 0。

接下来我们将配置 Grafana 可视化这些指标。


四、Grafana 仪表板配置与结果查看

4.1 配置 InfluxDB 数据源

  1. 登录 Grafana,点击左侧齿轮图标 → Data SourcesAdd data source

  2. 选择 InfluxDB

  3. URL 填写 http://<influxdb-ip>:8086,Database 填写 k6

  4. 保存并测试连接。

4.2 导入定制仪表板

我们基于官方模板调整了查询,使 Stat 面板显示的值与 CLI 输出完全一致。关键改动:

  • 对于累计指标(如 http_reqs),使用 last("value")max("value"),避免因时间分组导致的数值偏差。

  • 在趋势图中保留 GROUP BY time($__interval) 以展示随时间的变化。

下面是一份可直接导入的仪表板 JSON 核心面板示例(完整 JSON 略长,但核心查询如下):

  • 总请求数SELECT last("value") FROM "http_reqs" WHERE $timeFilter

  • 吞吐量SELECT last("value") / $__range_s FROM "http_reqs" WHERE $timeFilter

  • 响应时间统计minmedianmeanpercentile(95)max,均不带 GROUP BY。

  • 趋势图:保留分组聚合。

在 Grafana 中点击 +Import,粘贴完整 JSON 内容,选择数据源即可导入。

4.3 调整时间范围查看结果

导入后,点击右上角时间选择器,选择 Last 15 minutes 或自定义测试起止时间,确保覆盖整个测试窗口。此时,所有面板数值应与 CLI 输出保持一致(例如总请求数 10650,吞吐量 177.5 req/s,错误率 0%)。


五、结果对比与一致性验证

我们分别执行了 k6 与 JMeter 在相同并发(5 VU/线程)和相同时间(60 秒)下的测试,结果对比如下:

指标 JMeter k6
总请求数 10609 10650
吞吐量 (RPS) 176.9 177.3
平均响应时间 27 ms 27.76 ms
错误率 0% 0%

两者数据高度吻合,证明了 k6 的脚本逻辑与性能表现与 JMeter 等效。差异主要源于网络波动和系统缓存,属于正常范围。


六、总结与最佳实践

  1. Cookie 管理 :利用 response.cookies 可以简化 Cookie 提取,避免手动正则。

  2. CSV 驱动 :使用 SharedArray 确保所有 VU 共享数据,减少内存开销。

  3. 思考时间 :若需模拟无等待压力,务必移除 sleep,否则吞吐量将受限于 1/sleep_time

  4. InfluxDB 聚合 :累计指标应使用 lastmax,避免 sum 重复计数。

  5. Grafana 时间范围:确保仪表板时间范围覆盖测试时段,否则数据不完整。

通过本文的实践,我们成功构建了一套从脚本开发、并发测试到实时监控的完整 k6 工作流。无论您是刚开始接触 k6,还是希望从 JMeter 迁移,本文提供的方案都能为您提供有价值的参考。欢迎留言交流讨论。

相关推荐
Elastic 中国社区官方博客6 小时前
使用 Elasticsearch 作为 Grafana 的直接替代 Prometheus 后端
大数据·数据库·sql·elasticsearch·搜索引擎·grafana·prometheus
spider_xcxc1 天前
Prometheus + Grafana流程搭建总结
grafana·prometheus·云计算运维
c_zyer1 天前
一站式可观测新选择:OpenObserve 深度对标 ELK / Grafana+Prometheus / Netdata,附Docker一键部署实战
elk·grafana·prometheus·netdata·openobserve
孫治AllenSun3 天前
【Prometheus & Grafana】搭建可视化监控平台
grafana·prometheus
维C°4 天前
Grafana 上时间筛选
grafana
chen_ke_hao4 天前
Prometheus + Grafana监控平台-显卡集群监控
grafana·prometheus
SRETalk13 天前
Zabbix、Prometheus、Grafana、Nightingale,四个监控如何选型?
zabbix·grafana·prometheus·nightingale
何中应23 天前
Grafana面板没有数据问题排查
linux·grafana·prometheus
就改了23 天前
微服务指标监控一站式搭建:Prometheus抓取+Grafana大屏展示详解
微服务·grafana·prometheus