如何在JMeter中发送负载元素数量可变的请求并最终达到指定平均值?
JMeter动态调整请求节点数实现目标平均值方案
前置说明
利用JMeter全局属性props做跨线程的统计数据共享,结合JSR223前置处理器的动态逻辑,实现运行过程中实时校正节点生成数量,最终收敛到目标平均值3。
步骤1:初始化全局统计变量
添加setUp线程组,线程数设为1,循环数设为1,内部添加JSR223 Sampler,写入以下初始化代码:
// 初始化总请求计数 props.put("total_requests", 0L) // 初始化总节点计数 props.put("total_objects", 0L) // 配置目标平均值 props.put("target_average", 3G)
步骤2:编写动态生成节点的JSR223 Preprocessor逻辑
替换你原有HTTP请求下的JSR223 Preprocessor代码为以下内容,可根据实际需求调整权重参数:
import java.util.Random import java.math.BigDecimal def random = new Random() // 读取全局统计值 long totalReq = props.get("total_requests") as long long totalObj = props.get("total_objects") as long BigDecimal targetAvg = props.get("target_average") as BigDecimal final int MIN_COUNT = 1 final int MAX_COUNT = 99 int currentCount if (totalReq == 0) { // 首次请求直接生成1-3随机数 currentCount = random.nextInt(3) + 1 } else { BigDecimal currentAvg = (totalObj / totalReq) as BigDecimal if (currentAvg > targetAvg) { // 当前平均偏高,生成小数值拉低平均 currentCount = random.nextInt(2) + 1 // 1-2随机 } else if (currentAvg < targetAvg) { // 当前平均偏低,70%概率生成3-8,30%概率生成8-99,兼顾随机性和收敛速度 if (random.nextDouble() < 0.7) { currentCount = random.nextInt(6) + 3 } else { currentCount = random.nextInt(92) + 8 } } else { // 已达标,生成1-5随机数保持波动 currentCount = random.nextInt(5) + 1 } } // 边界校验,避免超出1-99范围 currentCount = Math.max(MIN_COUNT, Math.min(MAX_COUNT, currentCount)) // 生成对应数量的XML节点,可替换为你自己的节点生成逻辑 StringBuilder nodeBuilder = new StringBuilder() for (int i = 1; i <= currentCount; i++) { String reqId = String.format("ID%05d", i) String docId = String.valueOf(100000000 + i) nodeBuilder.append(" <object a='false' b='false' pReqID='").append(reqId).append("'>\n") nodeBuilder.append(" <al ad='2021-09-20' alc='bla' bla='2021-09-20T11:00:00.000Z' sn='AB8912' />\n") nodeBuilder.append(" <doc docType='P' docId='").append(docId).append("' name='test' date='12/31/2022' />\n") nodeBuilder.append(" </object>\n") } // 存入变量替换HTTP请求中的占位符,比如你的请求里占位符是${object_nodes} vars.put("object_nodes", nodeBuilder.toString()) // 线程安全更新全局统计值 synchronized (props) { props.put("total_requests", totalReq + 1) props.put("total_objects", totalObj + currentCount) }
步骤3:运行结束结果校验
添加tearDown线程组,线程数设为1,循环数设为1,内部添加JSR223 Sampler,写入代码打印最终统计结果:
import java.math.BigDecimal long totalReq = props.get("total_requests") as long long totalObj = props.get("total_objects") as long BigDecimal finalAvg = (totalObj / totalReq).setScale(2, BigDecimal.ROUND_HALF_UP) log.info("===== 最终统计结果 =====") log.info("总请求数:{}", totalReq) log.info("总节点数:{}", totalObj) log.info("平均节点数:{}", finalAvg)
运行结束后查看jmeter.log文件即可获取最终平均值,运行时长越长,结果越接近目标值3。
注意事项
- 统计值必须存在全局属性
props中,不要用单线程独有vars存储,避免多线程下统计异常 - 可根据实际需求调整概率权重,比如需要更多高节点数的样本时,可提高偏低平均时大数值的生成概率
- 高并发场景下
synchronized锁仅作用于计数更新逻辑,性能损耗可忽略,不会影响压测结果
内容的提问来源于stack exchange,提问作者JustNatural
相关产品推荐
相关产品推荐

