Grafana k6 性能测试

Grafana k6 是一款现代化的开源性能测试工具,专为测试API、微服务和网站而设计。

它采用JavaScript/TypeScript作为脚本语言,提供了简洁的API和强大的负载模拟能力,同时易于集成到CI/CD流程中。

本文将带您从基础到进阶,全面掌握k6的使用方法。

一、安装与环境准备

1.1 支持的操作系统

k6支持Windows、macOS和Linux,同时提供Docker镜像,方便在任何环境中运行。

1.2 安装步骤

macOS (Homebrew):

bash 复制代码
brew install k6

Windows (Chocolatey):

bash 复制代码
choco install k6

Linux (Ubuntu/Debian):

bash 复制代码
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C3959F7F5288
echo "deb https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list
sudo apt update && sudo apt install k6

Docker:

bash 复制代码
docker pull grafana/k6

1.3 验证安装

安装完成后,运行以下命令验证:

bash 复制代码
k6 version

如果安装成功,会显示类似以下内容:

复制代码
k6 v0.49.0 ((devel), go1.21.0, linux/amd64)

二、k6核心概念

在编写测试脚本前,理解k6的核心概念至关重要:

  1. 虚拟用户(VUs): 模拟真实用户的并发单元,每个VU独立执行脚本逻辑

  2. 场景(Scenarios): 定义测试的负载模式,如并发数、持续时间、递增方式等

  3. 生命周期:

    • init阶段: 脚本最外层代码,只执行一次,用于导入模块和定义全局变量
    • setup函数: 测试开始前执行一次,用于准备测试数据
    • VU函数: 每个虚拟用户重复执行的核心测试逻辑
    • teardown函数: 测试结束后执行一次,用于清理测试环境
  4. 指标(Metrics): 衡量系统性能的数据,如响应时间、错误率等

  5. 检查(Checks): 验证系统响应是否符合预期的断言机制

  6. 阈值(Thresholds): 定义性能指标的可接受范围,用于自动判断测试是否通过

三、第一个k6测试脚本

让我们从一个简单的HTTP GET请求测试开始,创建文件basic-test.js

javascript 复制代码
import http from 'k6/http';
import { check, sleep } from 'k6';

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

// 虚拟用户执行的主要函数
export default function() {
  // 发送GET请求
  const res = http.get('https://httpbin.test.k6.io/get');
  
  // 检查响应是否符合预期
  check(res, {
    '状态码为200': (r) => r.status === 200,
    '响应时间小于500ms': (r) => r.timings.duration < 500,
  });
  
  // 每个迭代后暂停1秒,模拟用户思考时间
  sleep(1);
}

3.1 脚本解析

  1. 导入模块 : 我们导入了http模块用于发送HTTP请求,check用于验证响应,sleep用于模拟用户等待时间。

  2. 配置选项:

    • vus: 同时运行的虚拟用户数量
    • duration: 测试总持续时间
  3. VU函数:

    • http.get(): 发送HTTP GET请求到指定URL
    • check(): 验证响应状态码和响应时间
    • sleep(1): 暂停1秒,避免请求过于密集

3.2 运行测试

执行以下命令运行测试:

bash 复制代码
k6 run basic-test.js

如果使用Docker,执行:

bash 复制代码
cat script.js | docker run --rm -i grafana/k6 run -

四、测试结果分析

测试运行时和结束后,k6会输出详细的测试结果。让我们理解一些关键指标:

复制代码
  █ TOTAL RESULTS

    checks_total.......: 440     14.035254/s
    checks_succeeded...: 100.00% 440 out of 440
    checks_failed......: 0.00%   0 out of 440

    ✓ ???????00
    ✓ ?????????500ms

    HTTP
    http_req_duration..............: avg=188.19ms min=60.93ms med=193.8ms max=338.83ms p(90)=309.64ms p(95)=310.83ms
      { expected_response:true }...: avg=188.19ms min=60.93ms med=193.8ms max=338.83ms p(90)=309.64ms p(95)=310.83ms
    http_req_failed................: 0.00%  0 out of 440
    http_reqs......................: 440    14.035254/s

    EXECUTION
    iteration_duration.............: avg=1.41s    min=1.36s   med=1.37s   max=2.26s    p(90)=1.38s    p(95)=1.4s
    iterations.....................: 220    7.017627/s
    vus............................: 10     min=10       max=10
    vus_max........................: 10     min=10       max=10

    NETWORK
    data_received..................: 772 kB 25 kB/s
    data_sent......................: 30 kB  958 B/s

关键指标解释:

  • http_req_duration : HTTP请求的总持续时间,包含了建立连接、发送请求、等待响应和接收响应的时间
    • p(90)p(95)是百分位数,表示90%或95%的请求在此时间内完成
  • http_req_failed: 失败请求的比例,理想情况下应为0
  • http_reqs: 每秒处理的请求数(RPS),反映系统吞吐量
  • vus: 当前并发虚拟用户数
  • iterations: 完成的测试迭代次数

五、进阶测试场景

5.1 复杂场景配置

k6的场景(Scenarios)功能允许您定义更复杂的负载模式。创建scenarios-test.js

javascript 复制代码
import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  scenarios: {
    // 场景1: 逐步增加负载
    ramp_up: {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '30s', target: 50 },  // 30秒内从0增加到50个VU
        { duration: '1m', target: 50 },   // 维持50个VU 1分钟
        { duration: '20s', target: 0 },   // 20秒内减少到0个VU
      ],
      gracefulRampDown: '10s',  // 优雅地减少负载
    },
    // 场景2: 恒定负载
    constant_load: {
      executor: 'constant-vus',
      vus: 20,
      duration: '2m',
      startTime: '1m50s',  // 在第一个场景开始后1分50秒启动
    },
  },
};

export default function() {
  const res = http.get('https://httpbin.test.k6.io/get');
  check(res, {
    '状态码为200': (r) => r.status === 200,
  });
  sleep(1);
}

k6提供多种执行器(executor)类型,适用于不同测试场景:

  • ramping-vus: 逐步增加或减少虚拟用户数
  • constant-vus: 维持恒定的虚拟用户数
  • constant-arrival-rate: 维持恒定的请求率
  • ramping-arrival-rate: 逐步增加或减少请求率
  • per-vu-iterations: 每个虚拟用户执行固定次数的迭代

5.2 设置阈值(Thresholds)

阈值用于定义性能指标的可接受范围,创建thresholds-test.js

javascript 复制代码
import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  vus: 10,
  duration: '30s',
  thresholds: {
    // 错误率必须小于1%
    http_req_failed: ['rate<0.01'],
    // 95%的请求响应时间必须小于500ms
    http_req_duration: ['p(95)<500'],
    // 每秒请求数至少为10
    http_reqs: ['rate>10'],
  },
};

export default function() {
  const res = http.get('https://httpbin.test.k6.io/get');
  check(res, {
    '状态码为200': (r) => r.status === 200,
  });
  sleep(1);
}

如果任何阈值未达标,k6将以非零状态码退出,这在CI/CD集成中非常有用。

5.3 处理认证与状态保持

大多数API测试需要处理认证,创建auth-test.js

javascript 复制代码
import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  vus: 5,
  duration: '30s',
};

// 测试开始前执行一次,用于登录获取token
export function setup() {
  const loginRes = http.post('https://test-api.k6.io/auth/token/login/', {
    username: 'test-user',
    password: 'test-passwd',
  });
  
  const token = loginRes.json('access');
  check(loginRes, {
    '登录成功': (r) => r.status === 200 && token !== '',
  });
  
  return { token: token };
}

// 每个虚拟用户执行的测试逻辑
export default function(data) {
  const params = {
    headers: {
      Authorization: `Bearer ${data.token}`,
      'Content-Type': 'application/json',
    },
  };
  
  // 访问受保护的API端点
  const res = http.get('https://test-api.k6.io/my/crocodiles/', params);
  
  check(res, {
    '状态码为200': (r) => r.status === 200,
    '响应包含鳄鱼数据': (r) => JSON.parse(r.body).length > 0,
  });
  
  sleep(1);
}

// 测试结束后执行一次,用于清理
export function teardown(data) {
  const params = {
    headers: {
      Authorization: `Bearer ${data.token}`,
    },
  };
  
  // 登出(如果API支持)
  const res = http.post('https://test-api.k6.io/auth/token/logout/', null, params);
  check(res, {
    '登出成功': (r) => r.status === 204,
  });
}

这个脚本展示了如何:

  1. setup函数中执行登录并获取认证token
  2. 将token传递给VU函数
  3. 在每个请求中使用token进行认证
  4. teardown函数中执行登出清理

5.4 测试数据管理

对于更真实的测试,我们需要使用不同的测试数据。创建data-driven-test.js

javascript 复制代码
import http from 'k6/http';
import { check, sleep, SharedArray } from 'k6';
import { Counter } from 'k6/metrics';

// 自定义指标,用于跟踪不同类型的请求
const successfulSearches = new Counter('successful_searches');
const failedSearches = new Counter('failed_searches');

// 从JSON文件加载测试数据(只在init阶段执行一次)
const data = new SharedArray('搜索关键词', function() {
  return JSON.parse(open('./search-terms.json')).terms;
});

export const options = {
  vus: 10,
  duration: '30s',
  thresholds: {
    http_req_duration: ['p(95)<500'],
    successful_searches: ['rate>0.95'],
  },
};

export default function() {
  // 为每个VU选择不同的关键词(基于VU ID和迭代次数)
  const term = data[(__VU * __ITER) % data.length];
  
  // 发送搜索请求
  const res = http.get(`https://httpbin.test.k6.io/get?search=${encodeURIComponent(term)}`);
  
  // 检查响应
  const isSuccessful = check(res, {
    '状态码为200': (r) => r.status === 200,
    '响应包含搜索词': (r) => r.body.includes(term),
  });
  
  // 更新自定义指标
  if (isSuccessful) {
    successfulSearches.add(1);
  } else {
    failedSearches.add(1);
  }
  
  sleep(1);
}

创建配套的search-terms.json文件:

json 复制代码
{
  "terms": ["k6", "performance", "testing", "api", "grafana", "load", "stress", "vus", "thresholds", "scenarios"]
}

这个脚本展示了:

  1. 使用SharedArray高效加载和共享测试数据
  2. 为不同的虚拟用户分配不同的测试数据
  3. 创建和使用自定义指标

六、结果导出与可视化

6.1 导出结果到文件

k6可以将测试结果导出为多种格式:

bash 复制代码
# 导出为JSON
k6 run --out json=results.json basic-test.js

# 导出为CSV
k6 run --out csv=results.csv basic-test.js

# 同时导出多种格式
k6 run --out json=results.json --out csv=results.csv basic-test.js

6.2 与Grafana集成

将k6与Grafana集成可以获得更强大的可视化和分析能力:

  1. 启动InfluxDB(作为数据存储):
bash 复制代码
docker run -d -p 8086:8086 \
  -e INFLUXDB_DB=k6 \
  --name influxdb \
  influxdb:1.8
  1. 启动Grafana:
bash 复制代码
docker run -d -p 3000:3000 \
  --link influxdb:influxdb \
  --name grafana \
  grafana/grafana
  1. 在Grafana中配置数据源:

  2. 导入k6官方仪表板:

    • 在Grafana中导入仪表板ID:1443
    • 选择配置好的InfluxDB数据源
  3. 运行测试并发送结果到InfluxDB:

bash 复制代码
k6 run --out influxdb=http://localhost:8086/k6 basic-test.js

现在,您可以在Grafana中实时查看测试指标和图表。

七、CI/CD集成

k6可以轻松集成到CI/CD流程中,作为质量门禁的一部分。以下是GitHub Actions的配置示例(创建.github/workflows/k6-test.yml):

yaml 复制代码
name: k6 Performance Test

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  k6-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup k6
        uses: k6io/action@v0.1
        with:
          k6-version: latest
          
      - name: Run k6 test
        run: k6 run tests/load-test.js
        
      - name: Upload test results
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: k6-results
          path: results.json

这个配置将在每次推送到main分支或创建PR时自动运行k6测试,如果测试失败(阈值未达标),CI流程也会失败。

八、最佳实践

  1. 从简单开始: 先创建基础测试,验证基本功能,再逐步增加复杂度

  2. 使用真实数据: 测试数据应尽可能接近生产环境的真实数据

  3. 定义明确的阈值: 根据业务需求和SLA定义清晰的性能阈值

  4. 逐步增加负载: 从低负载开始,逐步增加,观察系统在不同负载下的表现

  5. 隔离测试环境: 确保测试环境与生产环境隔离,避免影响真实用户

  6. 监控系统资源: 在测试期间监控服务器CPU、内存、磁盘I/O等资源使用情况

  7. 版本控制测试脚本: 将测试脚本纳入版本控制,与应用代码一起演进

  8. 自动化测试: 将性能测试集成到CI/CD流程中,尽早发现性能问题

  9. 分析瓶颈: 不仅关注响应时间,还要分析系统瓶颈所在(数据库、网络、应用服务器等)

  10. 定期执行: 定期运行性能测试,跟踪性能变化趋势

九、总结

通过本教程,您已经掌握了Grafana k6的核心功能和使用方法,包括:

  • 安装和配置k6环境
  • 理解k6的核心概念和生命周期
  • 编写基础和进阶的测试脚本
  • 配置复杂的测试场景和阈值
  • 处理认证和管理测试数据
  • 导出和可视化测试结果
  • 集成k6到CI/CD流程

k6提供了丰富的功能和灵活的API,能够满足从简单到复杂的各种性能测试需求。随着您对k6的深入使用,可以探索更多高级功能,如自定义指标、WebSocket测试、分布式测试等。

要了解更多信息,请参考k6官方文档:https://k6.io/docs/

相关推荐
麦兜*6 小时前
【Prometheus】 + Grafana构建【Redis】智能监控告警体系
java·spring boot·redis·spring·spring cloud·grafana·prometheus
川石课堂软件测试16 小时前
技术干货|使用Prometheus+Grafana监控Tomcat实例详解
redis·功能测试·单元测试·tomcat·测试用例·grafana·prometheus
SRETalk4 天前
Grafana侧重可视化,那多数据源告警呢?
grafana·nightingale·开源监控·夜莺监控
xiao-xiang5 天前
redis-集成prometheus监控(k8s)
数据库·redis·kubernetes·k8s·grafana·prometheus
计算机毕设定制辅导-无忧学长8 天前
Grafana 与 InfluxDB 可视化深度集成(二)
信息可视化·数据分析·grafana
云游8 天前
大模型性能指标的监控系统(prometheus3.5.0)和可视化工具(grafana12.1.0)基础篇
grafana·prometheus·可视化·监控
qq_232045579 天前
非容器方式安装Prometheus和Grafana,以及nginx配置访问Grafana
nginx·grafana·prometheus
测试开发Kevin9 天前
详解grafana k6 中stage的核心概念与作用
测试工具·压力测试·grafana