JMeter如何并行执行带数据依赖的两个测试脚本开展压测
跨场景依赖的双JMeter压测场景落地实现
核心设计逻辑
JMeter默认的线程局部变量仅对当前线程可见,跨线程组无法直接共享。结合两个场景要求各70独立并发、总计140并发并行运行1小时的要求,采用线程安全的全局阻塞队列做ID传递,避免静态参数列表容量不足、随机取数导致的ID重复消费问题。
分步配置操作
双线程组基础参数配置
- 新建两个独立并行执行的线程组,不设置串行依赖:
- 线程组1(对应创建类业务场景):设置70线程数,启动加速时长60秒,调度配置持续运行3600秒,循环策略设为永远
- 线程组2(对应更新类业务场景):设置70线程数,启动加速时长和线程组1对齐,调度同样持续3600秒,循环策略设为永远
- 配置时不要勾选线程组间的串行执行选项,保证两个场景的并发池完全独立,满足总140并发的要求
场景1侧ID动态入队配置
- 定位到场景1中创建成功、返回唯一ID的请求节点,追加JSON提取器或正则表达式提取器,配置匹配规则将返回的唯一ID存入当前线程局部变量,命名为
created_unique_id - 紧跟提取器追加JSR223后置处理器,脚本选择Groovy,写入逻辑将提取到的ID存入全局共享的线程安全阻塞队列,代码如下:
def createdId = vars.get("created_unique_id") if (createdId != null) { def idQueue = props.get("available_id_queue") // 首次执行时初始化线程安全的阻塞队列 if (idQueue == null) { idQueue = new java.util.concurrent.LinkedBlockingQueue() props.put("available_id_queue", idQueue) } // 非阻塞式将ID丢入队列,不影响场景1自身的执行效率 idQueue.offer(createdId) } - 注意:必须用JMeter全局属性
props做存储介质,不能用线程私有变量vars,否则跨线程组无法读到值
场景2侧ID动态拉取配置
- 定位到场景2中需要传入待更新ID的请求节点之前,追加JSR223前置处理器,脚本选择Groovy,从全局队列拉取可用ID存入当前线程的局部变量,代码如下:
def idQueue = props.get("available_id_queue") String targetUpdateId = null if (idQueue != null) { // 最长等待30秒拉取ID,避免队列空时无限阻塞线程 targetUpdateId = idQueue.poll(30, java.util.concurrent.TimeUnit.SECONDS) } if (targetUpdateId == null) { // 队列暂存为空时跳过本次迭代,不纳入错误率统计 log.warn("暂未获取到可用于更新的业务ID,跳过本次执行") ctx.getPreviousResult().setSuccessful(true) ctx.getPreviousResult().setResponseMessage("无可用ID临时跳过") } else { // 将拉取到的ID存入当前线程变量,供后续请求引用 vars.put("target_update_id", targetUpdateId) } - 在后续的更新类业务请求参数中,直接通过
${target_update_id}引用ID即可,和普通参数化逻辑完全一致
避坑要点
- 不要提前准备静态ID列表导入参数化,压测持续1小时会持续生成大量新ID,静态列表容量耗尽后会导致场景2无数据可跑
- 不要用全局Map做随机取数的ID存储,70个并发线程同时取数会出现同一个ID被多个更新请求同时消费的问题,LinkedBlockingQueue的poll操作是原子性的,从机制上避免了重复消费
- 不要为了等ID而设置无限阻塞逻辑,场景1出现短时业务抖动时,场景2的所有线程会被挂起,导致压测并发数达不到要求
- 队列不需要设置固定容量,场景1的生成速率和场景2的消费速率基本匹配,短时积压的ID仅占极小内存,不会影响压测机性能
内容的提问来源于stack exchange,提问作者Ajith Raman
相关产品推荐
相关产品推荐

