You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

K6测试中如何为所有VU统一更新刷新Token?

解决K6中全局Token定时刷新的问题

核心前提说明

K6的虚拟用户(VU)是完全隔离的,没有原生的VU间直接共享变量的机制——这是K6设计上的刻意限制,目的是避免并发竞态问题,保证每个VU的独立性和测试稳定性。所以直接在运行中的VU间同步变量是行不通的,得换思路。

可行解决方案

方案1:用k6/x/storage扩展实现全局共享存储

K6官方提供的xk6-storage扩展可以创建全局键值存储,所有VU都能读写这个存储,刚好满足统一Token的需求:

  1. 先安装扩展:k6 install github.com/grafana/xk6-storage
  2. 脚本里分两个场景:一个专门负责定时刷新Token并写入全局存储,另一个负责业务请求,每次请求前从存储拿最新Token
    示例代码:
    import storage from 'k6/x/storage';
    
    // 初始化全局Token存储
    const tokenStore = storage.newKeyValueStore('global_tokens');
    
    export const options = {
      scenarios: {
        token_refresher: {
          executor: 'constant-vus',
          vus: 1, // 只需要1个VU负责刷新
          duration: '3h', // 总测试时长
          exec: 'refreshToken',
        },
        main_traffic: {
          executor: 'constant-vus',
          vus: 50, // 业务请求的VU数量
          duration: '3h',
          exec: 'runMainTest',
        },
      },
    };
    
    // 专门的Token刷新函数
    export function refreshToken() {
      // 首次启动先拿初始Token
      let newToken = fetch('https://your-auth-domain/refresh', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ refresh_token: __ENV.REFRESH_TOKEN }),
      }).json().token;
      tokenStore.set('current_token', newToken);
    
      // 每小时刷新一次
      while (true) {
        sleep(3600);
        newToken = fetch('https://your-auth-domain/refresh', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ refresh_token: __ENV.REFRESH_TOKEN }),
        }).json().token;
        tokenStore.set('current_token', newToken);
      }
    }
    
    // 业务请求函数
    export function runMainTest() {
      // 每次请求前获取最新Token
      const currentToken = tokenStore.get('current_token');
      fetch('https://your-api-domain/business-endpoint', {
        headers: { 'Authorization': `Bearer ${currentToken}` },
      });
      sleep(1);
    }
    
    注意:这个扩展需要用自定义编译的K6二进制运行,或者用官方提供的Docker镜像。

方案2:分阶段切换场景,用setup()更新Token

如果不想用扩展,可以把测试拆成多个1小时的阶段,每个阶段开始前通过setup()获取新Token,该阶段的所有VU共用这个Token:

  1. 把总测试时长拆成“业务阶段+短暂停阶段”的循环
  2. 每个业务阶段启动新VU,用当前阶段setup()返回的Token
    示例代码:
    export const options = {
      stages: [
        { duration: '1h', target: 50 }, // 第一阶段,用初始Token
        { duration: '30s', target: 0 }, // 停掉旧VU,过渡30秒
        { duration: '1h', target: 50 }, // 第二阶段,新setup拿新Token
        { duration: '30s', target: 0 },
        // 按需添加更多阶段
      ],
    };
    
    export function setup() {
      // 每个阶段启动时,重新获取Token
      const token = fetch('https://your-auth-domain/login', {
        method: 'POST',
        body: JSON.stringify({ username: 'test_user', password: 'test_pass' }),
      }).json().token;
      return { token: token };
    }
    
    export default function(data) {
      // 使用当前阶段setup返回的Token发起请求
      fetch('https://your-api-domain/business-endpoint', {
        headers: { 'Authorization': `Bearer ${data.token}` },
      });
      sleep(1);
    }
    
    缺点:阶段切换时会有短暂的流量中断,适合对中断不敏感的测试场景。

方案3:VU本地缓存+外部存储同步

如果不能接受流量中断,也可以用外部存储(比如Redis)来同步Token:

  1. 部署一个Redis,用来存储最新Token和过期时间
  2. 用单独的进程(或K6的1个VU)每隔1小时刷新Token并写入Redis
  3. 每个VU本地缓存Token,每次请求前检查:如果本地Token过期,就从Redis拉取最新的
    这种方案灵活性最高,但需要额外维护外部存储,适合稳定性要求极高的场景。

最优方案选择

  • 追求简单无依赖,能接受短暂中断:选方案2
  • 需要无中断刷新,不想依赖外部服务:选方案1
  • 测试环境已有外部存储,要求最高稳定性:选方案3

内容的提问来源于stack exchange,提问作者Francisco K6

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 16:13:11