K6测试中如何为所有VU统一更新刷新Token?
解决K6中全局Token定时刷新的问题
核心前提说明
K6的虚拟用户(VU)是完全隔离的,没有原生的VU间直接共享变量的机制——这是K6设计上的刻意限制,目的是避免并发竞态问题,保证每个VU的独立性和测试稳定性。所以直接在运行中的VU间同步变量是行不通的,得换思路。
可行解决方案
方案1:用k6/x/storage扩展实现全局共享存储
K6官方提供的xk6-storage扩展可以创建全局键值存储,所有VU都能读写这个存储,刚好满足统一Token的需求:
- 先安装扩展:
k6 install github.com/grafana/xk6-storage - 脚本里分两个场景:一个专门负责定时刷新Token并写入全局存储,另一个负责业务请求,每次请求前从存储拿最新Token
示例代码:
注意:这个扩展需要用自定义编译的K6二进制运行,或者用官方提供的Docker镜像。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); }
方案2:分阶段切换场景,用setup()更新Token
如果不想用扩展,可以把测试拆成多个1小时的阶段,每个阶段开始前通过setup()获取新Token,该阶段的所有VU共用这个Token:
- 把总测试时长拆成“业务阶段+短暂停阶段”的循环
- 每个业务阶段启动新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:
- 部署一个Redis,用来存储最新Token和过期时间
- 用单独的进程(或K6的1个VU)每隔1小时刷新Token并写入Redis
- 每个VU本地缓存Token,每次请求前检查:如果本地Token过期,就从Redis拉取最新的
这种方案灵活性最高,但需要额外维护外部存储,适合稳定性要求极高的场景。
最优方案选择
- 追求简单无依赖,能接受短暂中断:选方案2
- 需要无中断刷新,不想依赖外部服务:选方案1
- 测试环境已有外部存储,要求最高稳定性:选方案3
内容的提问来源于stack exchange,提问作者Francisco K6
相关产品推荐
相关产品推荐

