使用 K6 进行性能测试:从安装到结果分析

263 阅读8分钟

使用 K6 进行性能测试:从安装到结果分析

K6 是一款现代化的开源性能测试工具,专为开发者和测试工程师设计。它使用 JavaScript 编写测试脚本,支持高并发负载测试,并提供丰富的性能指标和可视化报告。本文将介绍如何使用 Chocolatey 安装 K6,如何编写测试脚本,以及如何解读测试结果。


1. 使用 Chocolatey 安装 K6

Chocolatey 是 Windows 上的包管理工具,可以快速安装 K6。

安装步骤:

  1. 安装 Chocolatey(如果尚未安装):
    以管理员身份打开 PowerShell,运行以下命令:

    Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
    
  2. 安装 K6
    在 PowerShell 中运行以下命令:

    choco install k6
    
  3. 验证安装
    安装完成后,运行以下命令检查 K6 是否安装成功:

    k6 version
    

    如果显示 K6 的版本号,说明安装成功。


2. K6 的基本使用

K6 的核心是使用 JavaScript 编写测试脚本。以下是一个简单的 K6 测试脚本示例:

示例脚本:测试一个 API 的性能

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

// 测试配置
export let options = {
    vus: 10, // 虚拟用户数
    duration: '30s', // 测试持续时间
};

// 测试脚本
export default function () {
    let response = http.get('https://test-api.com/endpoint'); // 测试的目标 API
    check(response, {
        'Status is 200': (r) => r.status === 200, // 检查响应状态码是否为 200
        'Response time < 500ms': (r) => r.timings.duration < 500, // 检查响应时间是否小于 500ms
    });
    sleep(1); // 每个虚拟用户请求之间的间隔时间
}

脚本说明:

  1. import 语句
    导入 K6 的模块,例如 http 用于发送 HTTP 请求,check 用于断言,sleep 用于控制请求间隔。

  2. options 对象
    定义测试的配置参数:

    • vus:虚拟用户数(并发用户数)。
    • duration:测试持续时间。
  3. export default function
    定义测试逻辑,每个虚拟用户会重复执行此函数。

  4. http.get
    发送 HTTP GET 请求到目标 API。

  5. check
    对响应结果进行断言,例如检查状态码和响应时间。

  6. sleep
    控制每个虚拟用户请求之间的间隔时间,单位为秒。


3. 运行 K6 测试

将上述脚本保存为 script.js,然后在命令行中运行以下命令启动测试:

k6 run script.js

K6 会启动测试并输出实时结果。


4. 测试结果解读

K6 的测试结果会显示在终端中,包含以下关键指标:

示例输出:

running (30.0s), 00/10 VUs, 300 complete and 0 interrupted iterations
default ✓ [======================================] 10 VUs  30s

    ✓ Status is 200
    ✓ Response time < 500ms

    checks.........................: 100.00% ✓ 600       ✗ 0
    data_received..................: 1.2 MB  39 kB/s
    data_sent......................: 45 kB   1.5 kB/s
    http_req_blocked...............: avg=1.5ms   min=0s      med=1ms     max=20ms    p(90)=3ms     p(95)=5ms
    http_req_connecting............: avg=1ms     min=0s      med=1ms     max=15ms    p(90)=2ms     p(95)=3ms
    http_req_duration..............: avg=150ms   min=100ms   med=140ms   max=300ms   p(90)=200ms   p(95)=250ms
    http_req_receiving.............: avg=2ms     min=1ms     med=2ms     max=10ms    p(90)=3ms     p(95)=4ms
    http_req_sending...............: avg=1ms     min=0s      med=1ms     max=5ms     p(90)=2ms     p(95)=3ms
    http_req_waiting...............: avg=147ms   min=90ms    med=137ms   max=290ms   p(90)=195ms   p(95)=245ms
    http_reqs......................: 300      10.0/s
    iteration_duration.............: avg=1.15s   min=1.01s   med=1.1s    max=1.3s    p(90)=1.2s    p(95)=1.25s
    iterations.....................: 300      10.0/s
    vus............................: 10       min=10      max=10
    vus_max........................: 10       min=10      max=10

关键指标说明:

  1. checks
    断言的成功率。例如,100.00% ✓ 600 ✗ 0 表示所有断言都成功。

  2. data_receiveddata_sent
    测试期间接收和发送的数据量。

  3. http_req_duration
    每个 HTTP 请求的耗时,包括平均值(avg)、最小值(min)、最大值(max)和百分位数(p(90)p(95))。

  4. http_reqs
    总请求数和每秒请求数(RPS)。

  5. iterations
    总迭代次数和每秒迭代次数。

  6. vusvus_max
    虚拟用户数和最大虚拟用户数。


案例分析

 ✗ status is 2001% — ✓ 593 / ✗ 42328

     checks.........................: 1.38%  593 out of 42921
     data_received..................: 229 kB 1.3 kB/s
     data_sent......................: 1.1 MB 5.9 kB/s
     http_req_blocked...............: avg=41.93µs min=0s     med=0s      max=13.12ms p(90)=0s     p(95)=245.5µs
     http_req_connecting............: avg=36.97µs min=0s     med=0s      max=10.38ms p(90)=0s     p(95)=208.3µs
   ✗ http_req_duration..............: avg=8.54s   min=0s     med=0s      max=1m0s    p(90)=59.99s p(95)=59.99s
       { expected_response:true }...: avg=16.04s  min=13.34s med=16s     max=19.07s  p(90)=18.39s p(95)=18.79s
   ✗ http_req_failed................: 98.61% 42328 out of 42921
     http_req_receiving.............: avg=495ns   min=0s     med=0s      max=1.08ms  p(90)=0s     p(95)=0s
     http_req_sending...............: avg=4.4µs   min=0s     med=0s      max=2.5ms   p(90)=0s     p(95)=0s
     http_req_tls_handshaking.......: avg=0s      min=0s     med=0s      max=0s      p(90)=0s     p(95)=0s
     http_req_waiting...............: avg=8.54s   min=0s     med=0s      max=1m0s    p(90)=59.99s p(95)=59.99s
     http_reqs......................: 42921  238.456198/s
     iteration_duration.............: avg=8.63s   min=0s     med=86.85ms max=1m0s    p(90)=1m0s   p(95)=1m0s
     iterations.....................: 42921  238.456198/s
     vus............................: 18     min=18             max=5000
     vus_max........................: 5000   min=5000           max=5000

从提供的 K6 测试结果来看,系统的性能表现非常不理想,存在严重的性能问题。以下是对测试结果的详细分析:

1. 关键指标分析

**(1) **http_req_failed
  • 98.61% 42328 out of 42921
  • 分析
    • 请求失败率高达 98.61%,说明绝大多数请求都失败了。
    • 这是一个非常严重的问题,表明系统在高并发下无法正常处理请求。
**(2) **http_req_duration
  • avg=8.54s min=0s med=0s max=1m0s p(90)=59.99s p(95)=59.99s
  • 分析
    • 平均响应时间为 8.54 秒,最大响应时间达到 1 分钟
    • 90% 和 95% 的请求响应时间接近 60 秒,说明系统在高并发下响应极其缓慢。
    • 这是一个明显的性能瓶颈,可能是由于服务器资源不足、数据库瓶颈或代码效率低下导致的。
**(3) **http_reqs
  • 42921 238.456198/s
  • 分析
    • 总共发送了 42921 个请求,平均每秒发送 238.46 个请求
    • 虽然吞吐量看起来不低,但由于失败率极高,实际有效请求非常少。
**(4) **vusvus_max
  • vus: 18 min=18 max=5000vus_max: 5000 min=5000 max=5000
  • 分析
    • 测试的目标是达到 5000 个并发用户,但实际只有 18 个虚拟用户在运行。
    • 这表明系统在高并发下无法支持更多的虚拟用户,可能是由于资源耗尽或系统崩溃。
**(5) **checks
  • 1.38% 593 out of 42921
  • 分析
    • 只有 1.38% 的请求通过了检查(状态码为 200)。
    • 这与 http_req_failed 的失败率一致,进一步验证了系统的高失败率。
**(6) **data_receiveddata_sent
    • data_received: 229 kB 1.3 kB/s
    • data_sent: 1.1 MB 5.9 kB/s
  • 分析
    • 接收和发送的数据量较低,可能是由于请求失败率高,导致实际传输的数据量较少。

2. 问题总结

从测试结果可以看出,系统在高并发下存在以下问题:

  1. 极高的请求失败率(98.61%),表明系统无法处理高并发请求。
  2. 极长的响应时间(平均 8.54 秒,最大 60 秒),表明系统性能严重不足。
  3. 无法支持目标并发用户数(目标 5000,实际只有 18 个虚拟用户在运行),表明系统资源耗尽或崩溃。

常用脚本

测试一个 API 的性能,确定一下最高的并发数

通过逐渐增加压力的方式,进行压测

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

export let options = {
  stages: [
    { duration: '30s', target: 1000 },  // 在 30 秒内逐步增加到 1000 个并发用户
    { duration: '1m', target: 5000 },   // 在 1 分钟内逐步增加到 5000 个并发用户
    { duration: '2m', target: 10000 },  // 在 2 分钟内逐步增加到 10000 个并发用户
  ],
};

export default function () {
  let response = http.get('https://test-api.k6.io/public/crocodiles/');
  check(response, {
    'status is 200': (r) => r.status === 200, // 检查响应状态码
  });
}

2、设置 Bearer Token

import http from 'k6/http';

export default function () {
  // 设置 Token
  const token1 = __ENV.API_TOKEN; // 使用 k6 run -e API_TOKEN=your_token script.js 传递 Token
  
  //直接写入Token
  const token = 'your_bearer_token_here';
  const headers = {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json', // 根据需要设置其他请求头
  };

  // 发送请求
  let response = http.get('https://test-api.k6.io/secure-endpoint', { headers: headers });

  // 检查响应状态码
  if (response.status !== 200) {
    console.error('Request failed:', response.status, response.body);
  } else {
    console.log('Request succeeded:', response.body);
  }
}

3、设置 Cookie

import http from 'k6/http';

export default function () {
  // 设置 Cookie
  const token = 'your_cookie_token_here';
  const cookies = {
    'session_token': token,
  };

  // 发送请求
  let response = http.get('https://test-api.k6.io/secure-endpoint', { cookies: cookies });

  // 检查响应状态码
  if (response.status !== 200) {
    console.error('Request failed:', response.status, response.body);
  } else {
    console.log('Request succeeded:', response.body);
  }
}

4、 使用 SharedArray 加载用户列表

K6 的 SharedArray 可以高效地加载外部数据文件(如 JSON 或 CSV),并确保数据在多个虚拟用户之间共享。

示例:加载 JSON 文件 假设你有一个 users.json 文件,内容如下:

[
  {"username": "user1", "userId": "101"},
  {"username": "user2", "userId": "102"},
  {"username": "user3", "userId": "103"}
]

在 K6 脚本中加载并使用这些数据:

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

// 加载用户列表
const users = new SharedArray('users', function () {
  return JSON.parse(open('./users.json'));
});

export let options = {
  vus: users.length, // 设置虚拟用户数为用户列表的长度
  iterations: users.length,     // 每个虚拟用户只运行一次
};

export default function () {
  // 获取当前虚拟用户对应的用户数据
  const user = users[__VU - 1]; // __VU 是当前虚拟用户的 ID(从 1 开始)
  const url = `http://https://test-api.k6.io/secure-endpoint?userId=${user.userId}`;

  // 发送请求
  let response = http.get(url);
  check(response, {
    'status is 200': (r) => r.status === 200, // 检查响应状态码
  });
}

脚本说明

  • SharedArray:用于加载用户列表,并确保数据在多个虚拟用户之间共享。
  • vus: users.length:设置虚拟用户数为用户列表的长度,确保每个用户对应一个虚拟用户。
  • iterations: 1:每个虚拟用户只运行一次,确保每个用户只被测试一次。
  • __VU:当前虚拟用户的 ID(从 1 开始),通过 __VU - 1 可以获取用户列表中的对应数据。

5. 高级功能

  1. 分布式负载测试
    使用 k6 cloud 命令将测试分布到多个节点,模拟更高并发。

  2. 生成 HTML 报告
    使用 k6 run --out json=result.json script.js 生成 JSON 格式的测试结果,然后使用工具(如 k6-to-junit)转换为 HTML 报告。

  3. 集成 CI/CD
    将 K6 集成到 CI/CD 流水线中,自动化性能测试。

  4. 输出到influxdb中
    k6 run --out influxdb=http://localhost:8086/k6 script.js


总结

K6 是一款功能强大且易于使用的性能测试工具,适合测试 API、网站和后端服务的性能。通过 Chocolatey 可以快速安装 K6,使用 JavaScript 编写测试脚本,并通过丰富的指标分析测试结果。无论是开发、测试还是运维团队,K6 都能帮助您轻松实现性能测试目标。