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的核心概念至关重要:
- 
虚拟用户(VUs): 模拟真实用户的并发单元,每个VU独立执行脚本逻辑
 - 
场景(Scenarios): 定义测试的负载模式,如并发数、持续时间、递增方式等
 - 
生命周期:
init阶段: 脚本最外层代码,只执行一次,用于导入模块和定义全局变量setup函数: 测试开始前执行一次,用于准备测试数据VU函数: 每个虚拟用户重复执行的核心测试逻辑teardown函数: 测试结束后执行一次,用于清理测试环境
 - 
指标(Metrics): 衡量系统性能的数据,如响应时间、错误率等
 - 
检查(Checks): 验证系统响应是否符合预期的断言机制
 - 
阈值(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 脚本解析
- 
导入模块 : 我们导入了
http模块用于发送HTTP请求,check用于验证响应,sleep用于模拟用户等待时间。 - 
配置选项:
vus: 同时运行的虚拟用户数量duration: 测试总持续时间
 - 
VU函数:
http.get(): 发送HTTP GET请求到指定URLcheck(): 验证响应状态码和响应时间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,
  });
}
        这个脚本展示了如何:
- 在
setup函数中执行登录并获取认证token - 将token传递给VU函数
 - 在每个请求中使用token进行认证
 - 在
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"]
}
        这个脚本展示了:
- 使用
SharedArray高效加载和共享测试数据 - 为不同的虚拟用户分配不同的测试数据
 - 创建和使用自定义指标
 
六、结果导出与可视化
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集成可以获得更强大的可视化和分析能力:
- 启动InfluxDB(作为数据存储):
 
            
            
              bash
              
              
            
          
          docker run -d -p 8086:8086 \
  -e INFLUXDB_DB=k6 \
  --name influxdb \
  influxdb:1.8
        - 启动Grafana:
 
            
            
              bash
              
              
            
          
          docker run -d -p 3000:3000 \
  --link influxdb:influxdb \
  --name grafana \
  grafana/grafana
        - 
在Grafana中配置数据源:
- 访问http://localhost:3000(默认用户名/密码:admin/admin)
 - 添加InfluxDB数据源,URL设置为http://influxdb:8086,数据库名为k6
 
 - 
导入k6官方仪表板:
- 在Grafana中导入仪表板ID:1443
 - 选择配置好的InfluxDB数据源
 
 - 
运行测试并发送结果到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流程也会失败。
八、最佳实践
- 
从简单开始: 先创建基础测试,验证基本功能,再逐步增加复杂度
 - 
使用真实数据: 测试数据应尽可能接近生产环境的真实数据
 - 
定义明确的阈值: 根据业务需求和SLA定义清晰的性能阈值
 - 
逐步增加负载: 从低负载开始,逐步增加,观察系统在不同负载下的表现
 - 
隔离测试环境: 确保测试环境与生产环境隔离,避免影响真实用户
 - 
监控系统资源: 在测试期间监控服务器CPU、内存、磁盘I/O等资源使用情况
 - 
版本控制测试脚本: 将测试脚本纳入版本控制,与应用代码一起演进
 - 
自动化测试: 将性能测试集成到CI/CD流程中,尽早发现性能问题
 - 
分析瓶颈: 不仅关注响应时间,还要分析系统瓶颈所在(数据库、网络、应用服务器等)
 - 
定期执行: 定期运行性能测试,跟踪性能变化趋势
 
九、总结
通过本教程,您已经掌握了Grafana k6的核心功能和使用方法,包括:
- 安装和配置k6环境
 - 理解k6的核心概念和生命周期
 - 编写基础和进阶的测试脚本
 - 配置复杂的测试场景和阈值
 - 处理认证和管理测试数据
 - 导出和可视化测试结果
 - 集成k6到CI/CD流程
 
k6提供了丰富的功能和灵活的API,能够满足从简单到复杂的各种性能测试需求。随着您对k6的深入使用,可以探索更多高级功能,如自定义指标、WebSocket测试、分布式测试等。
要了解更多信息,请参考k6官方文档:https://k6.io/docs/