1. 项目概述:为什么前端/Node.js开发者需要关注K6?

如果你是一名前端或者Node.js开发者,每天打交道的是Vue、React、Next.js,或者用Node.js写写API、搞搞全栈,那么“性能测试”这个词对你来说,可能既熟悉又陌生。熟悉是因为你肯定听过,知道它很重要;陌生是因为它似乎总属于另一个领域——运维、测试或者后端工程师的“地盘”。你可能会想,我写业务逻辑、调接口、优化页面渲染已经够忙了,性能测试是不是还得去学JMeter那种复杂的工具,或者去折腾LoadRunner那种“上古神器”?

这就是K6出现并迅速在开发者社区走红的原因。它彻底改变了游戏规则。K6的核心设计理念就是 为开发者而生 ,尤其是为我们这些JavaScript/Node.js生态的开发者。它允许你直接用你熟悉的ES6+ JavaScript来编写性能测试脚本。这意味着,你不再需要为了压测一个API,去学习一门新的脚本语言(比如JMeter的Groovy/JMeter语法),或者去配置一堆繁琐的GUI界面。你可以用你写业务代码的同一套思维、同一种语言,甚至同一个编辑器(比如VSCode),来定义你的性能测试场景:并发用户怎么模拟、请求怎么发、断言怎么写、数据怎么参数化。

想象一下这个场景:你刚用Express.js或者NestJS写完了一个用户登录的API。你想知道它在100个用户同时登录时表现如何。传统方式你可能得打开另一个软件,笨拙地录制脚本或者手动填写各种表单。而用K6,你只需要新建一个 login_test.js 文件,用 fetch 或者 http 模块(K6内置了类似的API)写下请求,然后用 export default function() 定义虚拟用户的行为,最后在命令行用 k6 run login_test.js --vus 100 --duration 30s 就能看到结果。整个流程和你写一个Node.js脚本调用API进行集成测试,几乎没有任何认知负担。

这不仅仅是工具上的便利,更是思维上的融合。性能测试不再是项目尾声的一个独立环节,而是可以像单元测试、集成测试一样,融入你的开发工作流。你可以在本地开发时快速验证接口性能,可以在CI/CD流水线中自动执行性能回归测试,确保新提交的代码没有引入性能衰退。对于全栈开发者而言,这简直是如虎添翼。你能用同一门语言,从前端写到后端,再写到性能测试,实现真正的“闭环”。

所以,当看到“用你熟悉的JavaScript玩转性能测试”这个标题时,它指向的不仅仅是一个工具教程,更是一种效率和工作模式的进化。它让性能测试的门槛降低到了所有JavaScript开发者触手可及的程度。接下来,我们就深入K6的世界,看看如何从零开始,把它变成你开发工具箱中一件得心应手的利器。

2. K6核心概念与快速上手

在开始写脚本之前,我们需要先理解K6的几个核心概念,这能帮助你更好地设计测试场景。K6虽然用JS写脚本,但其模型和传统LoadRunner、JMeter是相通的,只是表达方式更程序员友好。

2.1 核心架构与关键术语

K6是一个 开源 的、 开发者友好 的性能测试工具,使用Go语言编写,因此它本身执行效率极高,单个进程就能模拟成千上万的虚拟用户(VUs)。它采用 协程(goroutine) 模型来高效管理这些虚拟用户,资源消耗远低于传统的基于线程或进程的工具。

你需要理解的几个关键术语:

  1. 虚拟用户(Virtual User, VU) :模拟真实用户行为的执行实体。一个VU会独立、并发地执行你定义的测试脚本( default 函数)。 --vus 100 就表示启动100个这样的并发实体。
  2. 迭代(Iteration) :一个VU完整执行一次 default 函数的过程,称为一次迭代。例如,一个用户登录-查看主页-退出的流程可以是一个迭代。
  3. 阶段(Stages) :用于定义测试负载随时间变化的模型。比如,你可以定义在30秒内逐渐将用户数从0上升到100(ramp-up),保持100用户运行2分钟,然后在30秒内逐渐下降到0(ramp-down)。这比固定并发数更贴近真实场景。
  4. 指标(Metrics) :K6自动收集并输出大量的性能指标,这是测试结果的核心。主要包括:
    • http_req_duration(请求持续时间) :最重要的指标之一,通常我们关注它的平均值、中位数、p(95)、p(99)等分位值。 p(95) < 200ms 意味着95%的请求在200毫秒内完成。
    • http_reqs(请求总数) :每秒请求数(RPS)就是基于这个指标计算的。
    • iterations(迭代次数) :所有VU完成的迭代总数。
    • vus(虚拟用户数) :当前活跃的虚拟用户数。
    • checks(检查点) thresholds(阈值) checks 用于断言某个条件是否成立(如HTTP状态码是否为200), thresholds 则用于定义整个测试必须满足的性能标准(如p(95)必须小于1秒),不满足则测试失败。

2.2 环境安装与第一个脚本

安装K6非常简单,它提供了各种平台的安装包。对于Mac用户,推荐使用Homebrew:

brew install k6

对于Windows用户,可以使用Chocolatey、Scoop,或者直接下载MSI安装包。Linux用户可以使用包管理器或下载二进制文件。安装完成后,在终端输入 k6 version 验证。

现在,让我们创建第一个脚本文件 first_test.js 。这个脚本将访问一个公开的测试API。

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

// 1. 初始化选项(Init Stage)
// 在这里可以配置测试的全局参数,但更常见的做法是使用命令行参数或单独的选项对象。
// export const options = {
//   vus: 10,
//   duration: '30s',
// };

// 2. 虚拟用户代码(VU Stage)
// 这是每个虚拟用户会反复执行的函数。
export default function () {
  // 发送一个GET请求到测试网站
  let response = http.get('https://test-api.k6.io/public/crocodiles/');

  // 添加检查点(断言):验证状态码是200,并且响应体不为空
  check(response, {
    'status is 200': (r) => r.status === 200,
    'response body exists': (r) => r.body.length > 0,
  });

  // 模拟用户思考时间,每个VU在每次迭代后暂停1秒
  sleep(1);
}

注意 :K6脚本使用ES6模块系统( import/export ),并且运行在K6自己的JavaScript运行时中, 它不是Node.js环境 。这意味着你不能使用Node.js特有的API(如 fs path 模块)或者NPM包。K6提供了它自己的一套内置模块( k6/http , k6/checks , k6/metrics 等)来满足测试需求。

保存文件后,打开终端,进入脚本所在目录,执行:

k6 run first_test.js --vus 5 --duration 10s

这条命令会启动5个虚拟用户,持续运行10秒。你会看到控制台输出详细的测试结果摘要,包括请求耗时、迭代次数、检查点通过率等。

2.3 测试配置的几种方式

上面我们通过命令行参数 --vus --duration 来配置测试。但在实际项目中,更推荐将配置写在脚本的 options 对象中,这样便于版本管理和复用。

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

export const options = {
  // 定义阶段:更真实的负载模型
  stages: [
    { duration: '30s', target: 20 }, // 30秒内爬升到20个VU
    { duration: '1m30s', target: 20 }, // 在20VU保持1分30秒
    { duration: '20s', target: 0 }, // 20秒内下降到0
  ],
  // 定义阈值:性能达标线
  thresholds: {
    http_req_duration: ['p(95)<500', 'p(99)<1000'], // 95%的请求<500ms,99%<1000ms
    'http_req_duration{type:API}': ['p(95)<200'], // 可以对特定请求打标签,单独设置阈值
    checks: ['rate>0.95'], // 检查点总体通过率需>95%
    http_req_failed: ['rate<0.01'], // 请求失败率需<1%
  },
};

export default function () {
  // 给这个请求打上标签,便于在结果和阈值中区分
  let res = http.get('https://test-api.k6.io/public/crocodiles/', {
    tags: { type: 'API', name: 'GetCrocodiles' },
  });

  check(res, {
    'status is 200': (r) => r.status === 200,
  });

  sleep(Math.random() * 2); // 随机等待0-2秒,模拟更真实的用户行为
}

这种方式将负载模型、性能标准都内聚在脚本里,执行时只需简单的 k6 run script.js 即可。命令行参数会覆盖脚本中的 options ,这为不同环境(如预发、生产)运行不同强度的测试提供了灵活性。

3. 编写真实场景的测试脚本

掌握了基础之后,我们来构建更贴近真实项目的测试脚本。一个典型的Web应用场景可能包括:登录、浏览列表、查看详情、提交表单等。我们将把这些步骤串联起来,并加入数据参数化、思考时间、事务等高级特性。

3.1 模拟用户登录与会话保持

对于需要认证的API,我们需要先登录获取令牌(如JWT),并在后续请求中携带。K6的 http 模块会自动管理Cookie,但像Token这种通常放在Header里的,需要手动处理。

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

// 使用SharedArray在VU间高效共享只读测试数据(如用户账号)
const users = new SharedArray('users', function () {
  // 这里可以是从JSON文件读取,但注意K6不能直接使用fs模块。
  // 通常通过`open()`函数在初始化阶段读取。
  return JSON.parse(open('./test_users.json'));
});

export const options = {
  stages: [
    { duration: '1m', target: 50 },
    { duration: '3m', target: 50 },
    { duration: '30s', target: 0 },
  ],
};

// 全局变量,用于在VU的多次迭代间保存token
let authToken;

// setup函数会在所有VU启动前执行一次,常用于初始化、获取全局认证信息等
export function setup() {
  const loginRes = http.post('https://your-api.com/auth/login', JSON.stringify({
    username: 'testuser',
    password: 'testpass',
  }), {
    headers: { 'Content-Type': 'application/json' },
  });

  check(loginRes, { 'login成功': (r) => r.status === 200 && r.json('token') });

  const token = loginRes.json('token');
  console.log(`Setup获取到Token: ${token.substring(0, 20)}...`);
  return { token }; // setup的返回值会作为data参数传递给default函数
}

// teardown函数会在所有VU执行结束后运行一次,用于清理
export function teardown(data) {
  console.log(`测试结束,清理资源。Token是: ${data.token.substring(0, 20)}...`);
}

export default function (data) {
  // data来自setup函数的返回值
  const token = data.token;
  const headers = {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json',
  };

  // 示例1:获取用户信息(需要认证)
  const myProfile = http.get('https://your-api.com/users/me', { headers });
  check(myProfile, { '获取个人信息成功': (r) => r.status === 200 });

  // 示例2:参数化:从共享数组中随机取一个用户ID来查询其详情
  const randomUser = users[Math.floor(Math.random() * users.length)];
  const userDetail = http.get(`https://your-api.com/users/${randomUser.id}`, { headers });
  check(userDetail, { '获取用户详情成功': (r) => r.status === 200 });

  // 模拟用户操作间隔
  sleep(1);
}

实操心得 SharedArray 是性能关键。如果你用普通的数组来存储测试数据,每个VU都会复制一份,消耗大量内存。 SharedArray 在所有VU间共享内存,非常适合存储大量的只读测试数据(如用户名、产品ID列表)。但记住,它是只读的。

3.2 组织复杂场景:事务与分组

当测试流程包含多个步骤时,使用 transaction group 可以让你的脚本更清晰,并且能在结果报告中聚合这些步骤的指标。

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

export const options = { vus: 1, duration: '10s' }; // 先用1个VU调试

export default function () {
  // 使用group对逻辑相关的操作进行分组
  group('用户浏览商品流程', function () {
    // 事务:将多个请求/操作包装成一个业务事务,K6会统计其总耗时
    let browseTime = http.get('https://your-api.com/products');
    check(browseTime, { '浏览列表成功': (r) => r.status === 200 });

    // 假设从列表响应中提取第一个商品ID(这里简化处理)
    // 实际场景可能需要解析JSON:let productId = browseTime.json()[0].id;
    let productId = 123;

    let detailTime = http.get(`https://your-api.com/products/${productId}`);
    check(detailTime, { '查看详情成功': (r) => r.status === 200 });

    sleep(0.5);
  }); // group结束

  group('用户下单流程', function () {
    let cartRes = http.post('https://your-api.com/cart', JSON.stringify({ productId: 123, quantity: 1 }), {
      headers: { 'Content-Type': 'application/json' },
    });
    check(cartRes, { '加入购物车成功': (r) => r.status === 201 });

    let orderRes = http.post('https://your-api.com/orders', JSON.stringify({ cartId: cartRes.json('id') }), {
      headers: { 'Content-Type': 'application/json' },
    });
    check(orderRes, { '创建订单成功': (r) => r.status === 201 });

    sleep(1);
  });
}

运行后,在输出结果中,你不仅能看到总的 http_req_duration ,还能看到名为 group_duration 的指标,它记录了每个 group 的总执行时间。 transaction 的用法类似,但它更侧重于一个完整的业务操作耗时。

3.3 处理动态数据与关联

性能测试中经常需要处理动态数据,比如上一个请求的响应结果,是下一个请求的参数。这就是“关联”。

import http from 'k6/http';
import { check, sleep } from 'k6';
import { html } from 'k6/html'; // 用于解析HTML(如果测试网页)

export default function () {
  // 1. 获取一个动态生成的令牌(例如CSRF Token)
  let getFormRes = http.get('https://your-site.com/contact');
  // 使用html模块解析响应,提取隐藏字段的值
  let doc = html.parse(getFormRes.body);
  let csrfToken = doc.find('input[name=csrf_token]').attr('value');

  // 2. 使用这个令牌提交表单
  let payload = {
    name: 'K6 Tester',
    email: 'test@k6.io',
    message: 'This is a performance test message.',
    csrf_token: csrfToken,
  };

  let submitRes = http.post('https://your-site.com/contact', payload, {
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  });

  check(submitRes, {
    '表单提交成功': (r) => r.status === 200,
    '返回成功消息': (r) => r.body.includes('Thank you'),
  });

  sleep(2);
}

对于JSON API,关联更简单,直接使用 .json() 方法提取字段即可。关键在于,要确保你提取数据的请求在脚本中位于使用该数据的请求之前,并且逻辑正确。

4. 高级特性与集成实践

当基础脚本能满足需求后,我们可以探索K6更强大的功能,将其集成到现代开发流程中,发挥最大价值。

4.1 自定义指标与阈值告警

除了内置的HTTP指标,你可以定义自己的业务指标,比如订单创建耗时、特定计算逻辑的耗时等。

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

// 创建自定义趋势指标,用于记录“订单创建总耗时”
const orderCreationTime = new trend('order_creation_time', true);

export const options = {
  thresholds: {
    'order_creation_time': ['p(95)<1000'], // 为自定义指标设置阈值
  },
};

export default function () {
  group('创建订单', function () {
    const start = new Date(); // 记录开始时间

    // ... 执行一系列加入购物车、确认地址、支付等请求 ...
    let addToCart = http.post('...');
    let confirmAddress = http.get('...');
    let submitOrder = http.post('...'); // 假设这是最终创建订单的请求

    const end = new Date(); // 记录结束时间
    const duration = end - start; // 计算总耗时(毫秒)

    // 将耗时添加到自定义指标中
    orderCreationTime.add(duration);

    check(submitOrder, { '订单创建成功': (r) => r.status === 201 });
  });

  sleep(1);
}

trend 指标类型会记录所有值并计算分位数。你还可以使用 counter (计数器)、 gauge (瞬时值)、 rate (比率)等类型。结合 thresholds ,当自定义指标不达标时,测试会失败,这非常适合在CI中做自动化性能门禁。

4.2 与CI/CD管道集成(GitHub Actions示例)

将K6测试集成到CI/CD中是实现“性能左移”的关键。这里以GitHub Actions为例。

在你的项目根目录创建 .github/workflows/k6-performance.yml

name: K6 Performance Tests
on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]
  # 也可以手动触发
  workflow_dispatch:

jobs:
  performance:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Install K6
        run: |
          sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
          echo "deb https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list
          sudo apt-get update
          sudo apt-get install k6

      - name: Run K6 smoke test (低负载)
        run: |
          k6 run --vus 5 --duration 30s scripts/smoke_test.js
        env:
          API_BASE_URL: ${{ secrets.STAGING_API_URL }} # 使用环境变量传递测试地址

      - name: Run K6 load test (标准负载) - 仅在推送到main或手动触发时执行
        if: github.event_name == 'push' && github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch'
        run: |
          k6 run --out json=results.json scripts/load_test.js
          # 你可以在这里添加步骤,将results.json上传到性能分析平台(如Grafana+InfluxDB)

      - name: Check performance thresholds
        # 使用社区Action来解析输出并设置检查状态
        uses: grafana/k6-action@v0.3.0
        with:
          filename: scripts/threshold_test.js # 这个脚本必须包含thresholds配置
          flags: --summary-export=summary.json
        env:
          API_BASE_URL: ${{ secrets.STAGING_API_URL }}

这个工作流做了几件事:

  1. 在每次推送或PR时,运行一个轻量级的冒烟测试( smoke_test.js ),快速验证API基本可用性。
  2. 仅在代码合并到主分支或手动触发时,运行完整的负载测试( load_test.js ),避免资源浪费。
  3. 使用专门的 threshold_test.js k6-action 来执行带阈值的测试,如果任何阈值不满足,该步骤会失败,从而阻止合并或发出警报。

4.3 结果输出与可视化

命令行输出虽然详细,但不便于历史对比和团队共享。K6支持将结果输出到多种外部系统。

输出到JSON文件:

k6 run --out json=my_test_result.json script.js

生成的JSON文件可以导入到其他工具进行分析。

输出到InfluxDB + Grafana(推荐用于监控): 这是最强大的可视化方案。首先需要运行InfluxDB和Grafana(可以用Docker快速搭建)。

# 运行InfluxDB和Grafana
docker run -d -p 8086:8086 influxdb:1.8
docker run -d -p 3000:3000 grafana/grafana

# 运行K6测试,并将结果推送到InfluxDB
k6 run --out influxdb=http://localhost:8086/k6 script.js

然后在Grafana中配置InfluxDB数据源,导入官方的K6仪表板模板(ID:2587),你就能看到一个实时、历史丰富的性能监控仪表盘,可以清晰地看到RPS、响应时间、错误率等指标随时间的变化曲线。

使用k6 Cloud: 如果你不想自己维护基础设施,可以考虑K6的商业云服务(k6 Cloud),它提供了更强大的分布式负载生成、更丰富的分析和团队协作功能。

5. 常见问题、调试技巧与性能调优

即使脚本写好了,在运行过程中也可能遇到各种问题。这里记录一些常见的坑和解决思路。

5.1 脚本调试与日志输出

K6脚本的调试不如Node.js方便,因为没有真正的“调试器”。主要依靠 console.log() 和检查点。

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

export let options = {
  vus: 1,
  iterations: 1, // 调试时,先用1个VU跑1次
};

export default function () {
  let res = http.get('https://httpbin.test.k6.io/status/404');
  
  // 打印详细信息到控制台
  console.log(`Response status: ${res.status}`);
  console.log(`Response body: ${res.body.substring(0, 200)}`); // 只打印前200字符
  console.log(`Response headers: ${JSON.stringify(res.headers)}`);

  // 使用check进行断言,失败信息会显示在总结里
  let checkResult = check(res, {
    'status is 200': (r) => r.status === 200,
    'body contains something': (r) => r.body.includes('expected string'),
  });

  if (!checkResult) {
    console.error('Check failed!'); // 可以输出更详细的错误上下文
  }
}

运行调试脚本时,使用 k6 run --verbose debug_script.js 可以获得更详细的内部日志。对于复杂的逻辑,可以先将负载设到最小( vus: 1, iterations: 1 ),确保单次执行逻辑正确,再逐步增加负载。

5.2 常见错误与排查

  1. ECONNREFUSED ETIMEDOUT

    • 原因 :目标服务器连接被拒绝或超时。
    • 排查 :首先确认目标URL是否正确、服务是否已启动。其次,检查本地网络或防火墙设置。如果是在CI环境中,确保Runner可以访问目标网络。高并发下出现,可能是服务器或中间件(如负载均衡器)的连接数限制被击穿。
  2. Socket hang up

    • 原因 :服务器端主动关闭了连接,而客户端(K6)还在尝试读写。
    • 排查 :这通常是服务器端问题。检查服务器应用日志,看是否有未处理的异常导致连接异常终止。也可能是服务器设置了过短的keep-alive超时时间,而K6的请求间隔太长。
  3. 内存使用量不断增长(Memory Leak)

    • 原因 :虽然K6本身是Go写的,内存管理很好,但你的JS脚本可能导致内存泄漏。
    • 排查 :检查脚本中是否在 default 函数内不断创建巨大的对象或数组,并且没有释放。避免在VU代码中无限增长全局或模块级数组。使用 SharedArray 处理只读大数据集。运行测试时用 k6 run --verbose script.js 2>&1 | grep -i mem 观察内存变化。
  4. 检查点(checks)大量失败,但请求本身可能成功

    • 原因 :断言条件写得太严格,或者对响应数据的解析出错。
    • 排查 :先打印出失败的响应状态码和部分内容,确认服务器返回的是你期望的数据格式。使用 try-catch 包裹 r.json() 解析,因为如果响应体不是合法JSON,会抛出异常导致整个VU迭代失败。
    let parsedBody;
    try {
      parsedBody = JSON.parse(r.body);
    } catch (e) {
      console.error(`Failed to parse JSON: ${e.message}, body: ${r.body.substring(0, 100)}`);
      return false; // 检查点返回false
    }
    return parsedBody.success === true;
    

5.3 性能测试脚本本身的性能调优

当你模拟成千上万的VU时,脚本本身的效率也变得重要。

  1. 减少 default 函数中的同步操作 default 函数执行得越快,单个VU能完成的迭代(RPS)就越多。避免在函数内进行复杂的计算或同步的“睡眠”( sleep 是必要的,但不要太长)。将不变的初始化工作移到 setup 中。
  2. 善用 SharedArray :如前所述,对于庞大的静态测试数据(如10万个用户ID),一定要用 SharedArray ,否则内存会爆。
  3. 谨慎使用 console.log :在高并发下,向控制台输出日志会成为巨大瓶颈,严重拖慢测试速度。仅在调试时使用,正式压测前务必移除或减少。
  4. 调整K6运行参数
    • --no-thresholds / --no-summary :如果不需实时计算阈值或显示最终摘要,可以禁用它们以节省少量资源。
    • --no-usage-report :禁用匿名使用报告。
    • 最重要的是: 确保运行K6的机器资源足够 (CPU、内存、网络带宽)。对于超高并发测试,考虑使用分布式执行(k6 Cloud或自建k6集群)。

5.4 解读测试结果报告

看懂K6的输出报告是分析性能瓶颈的基础。一份典型的总结报告包含:

data_received..............: 155 MB 2.6 MB/s
data_sent..................: 12 MB  199 kB/s
http_req_blocked...........: avg=1.05ms   min=0s      med=1us     max=342.63ms p(90)=2us     p(95)=3us
http_req_connecting........: avg=770.33µs min=0s      med=0s      max=238.8ms  p(90)=0s      p(95)=0s
http_req_duration..........: avg=45.99ms  min=10.65ms med=33.44ms max=1.18s    p(90)=78.98ms p(95)=112.43ms
http_req_receiving.........: avg=1.7ms    min=0s      med=1.01ms  max=102.14ms p(90)=3.02ms  p(95)=4.52ms
http_req_sending...........: avg=0s       min=0s      med=0s      max=1ms      p(90)=0s      p(95)=0s
http_req_waiting...........: avg=44.29ms  min=10.64ms med=32.39ms max=1.18s    p(90)=76.33ms p(95)=108.71ms
http_reqs..................: 15584 259.574444/s
iteration_duration.........: avg=1.05s    min=1.01s   med=1.04s   max=2.19s    p(90)=1.09s   p(95)=1.13s
iterations.................: 1558  25.941111/s
vus........................: 100   min=100 max=100
vus_max....................: 100
  • http_req_duration :总请求耗时。这是核心指标。关注 p(95) p(99) ,它们比平均值更能反映用户体验。
  • http_req_blocked / connecting :TCP连接建立或TLS握手前的阻塞时间。如果这个值很高,可能是DNS解析慢、客户端端口耗尽或网络问题。
  • http_req_sending :发送请求体到网络的时间。如果发送大量数据(如上传文件)时这个值高,可能是网络带宽不足或客户端性能瓶颈。
  • http_req_waiting (TTFB) : 等待服务器返回第一个字节的时间。 这是衡量服务器应用处理能力的黄金指标 。如果TTFB高,而 receiving 低,瓶颈几乎肯定在服务器端(应用代码、数据库、外部API调用慢)。
  • http_req_receiving :从网络接收响应体的时间。如果下载大文件时这个值高,可能是网络带宽或服务器出口带宽不足。
  • iterations http_reqs :总迭代数和请求数,以及它们的速率( iterations/s , reqs/s )。这是系统吞吐量的直接体现。

分析时,结合这些指标:如果 waiting (TTFB) 很高,就去查服务器日志、数据库慢查询、外部服务调用链。如果 receiving 很高且响应体很大,考虑是否启用压缩、减少不必要的数据传输。如果 connecting 很高,检查DNS、客户端机器网络配置和端口范围( net.ipv4.ip_local_port_range )。

从我个人的经验来看,K6最大的优势在于它让性能测试变成了一个“开发任务”。你不再需要切换思维上下文,用JavaScript就能描述复杂的用户行为,用代码管理测试场景和断言,这极大地提升了效率和测试的可靠性。将K6集成到CI/CD后,每次代码变更都能得到及时的性能反馈,真正做到了防患于未然。刚开始可能会觉得配置阈值、分析报告有点复杂,但一旦跑通几次,你就会发现这套流程比任何GUI工具都更可控、更强大。不妨从为一个简单的GET接口写一个30秒的测试开始,逐步将它应用到你的核心业务场景中去。

更多推荐