如何通过IBM MQ JMS点对点模式结合JMeter测量SuT的响应处理时间
方案验证与疑问解答
你设计的逻辑完全可行,是JMeter做异步JMS请求响应测试的标准实现方案,复杂度合理,以下是具体问题的解答和代码示例:
疑问1:Correlation ID的获取方法
你不需要通过读属性的方式获取Correlation ID,直接用JMS规范的标准API即可,避免拼写错误(你之前写的JMS_CorreationID拼写有误,很容易踩坑):
- 发送端:自己生成唯一ID作为Correlation ID,推荐用UUID,设置到待发送消息中即可,同时要求被测系统处理完请求后,将收到的Correlation ID原样写入响应消息的Correlation ID字段(这是MQ异步通信的通用约定)
- 消费端:收到响应消息后,直接调用
msg.getJMSCorrelationID()方法即可拿到对应的ID
发送端设置示例:
// 生成唯一Correlation ID def corrId = UUID.randomUUID().toString() // 消息对象设置Correlation ID message.setJMSCorrelationID(corrId)
疑问2:存储结构设计
不需要用ID列表,推荐用线程安全的ConcurrentHashMap存储键值对,键为Correlation ID,值为消息发送的时间戳,比列表查询效率更高(O(1)复杂度),完全适配高并发场景:
- 存储结构需要放在JMeter的全局
props对象中,因为你是跨线程组共享数据,线程私有vars对象无法实现跨线程组通信 - 你的判断逻辑是对的:消费到消息后拿ID去Map里查询,命中后删除对应键,再计算时间差
- 小优化:可以额外加定时清理逻辑,删掉超过超时时间的无效ID,避免内存泄漏
- 额外建议:直接存JMeter本地的发送时间戳,比读
JMS_IBM_PUTTIME更简单,还能避免MQ服务器和JMeter服务器时钟不同步导致的计算误差
疑问3:自定义SampleResult的响应时间
JSR223 Sampler内置的SampleResult对象提供了直接修改响应时间的方法,你不需要管采样器自身的执行时间,直接把计算出来的被测系统处理时间赋值即可:
def globalCorrMap = props.get("globalCorrMap") def corrId = msg.getJMSCorrelationID() def sendTime = globalCorrMap.get(corrId) // 计算被测系统处理时间 def sutProcessTime = System.currentTimeMillis() - sendTime // 直接设置采样结果的响应时间,单位为毫秒 SampleResult.setTime(sutProcessTime) // 可选配置:设置请求成功/失败状态、响应内容 SampleResult.setSuccessful(true) SampleResult.setResponseData(msg.getBody(String.class), "UTF-8") // 处理完移除ID globalCorrMap.remove(corrId)
疑问4:报告仅保留消费端结果
两种最简单的实现方式:
- 发送端的JSR223 Sampler直接调用
SampleResult.setIgnore()方法,该采样器的结果会完全被忽略,不会进入任何监听器和报告 - 如果需要保留发送端结果做排查,只需要在Aggregate Report监听器的配置项中,勾选「仅显示名称匹配的样本」,填写消费端Sampler的名称即可;生成HTML报告时可以在
user.properties中配置jmeter.reportgenerator.exporter.html.series_filter参数过滤样本
完整代码示例
setUp线程组JSR223元件(初始化)
// 初始化全局线程安全的Correlation ID存储Map props.put("globalCorrMap", new java.util.concurrent.ConcurrentHashMap<String, Long>()) // 这里放你原有的OUTBOUND.QUEUE消费连接初始化代码,连接对象也存在props中共享
发送端线程组JSR223 Sampler
import javax.jms.* def corrId = UUID.randomUUID().toString() // 这里放你原有创建消息、连接INBOUND.QUEUE的代码 Message message = session.createTextMessage("你的测试消息内容") message.setJMSCorrelationID(corrId) // 发送消息 producer.send(message) // 存储ID和发送时间 props.get("globalCorrMap").put(corrId, System.currentTimeMillis()) // 忽略发送端采样结果,不进入报告 SampleResult.setIgnore()
消费端线程组JSR223 Sampler
import javax.jms.* def globalCorrMap = props.get("globalCorrMap") // 按你需要的超时时间设置receive的参数,单位为毫秒,比如10秒超时 Message msg = consumer.receive(10000) if (msg == null) { SampleResult.setSuccessful(false) SampleResult.setResponseMessage("响应超时") return } def corrId = msg.getJMSCorrelationID() if (!globalCorrMap.containsKey(corrId)) { // 非本次测试的消息直接忽略 SampleResult.setIgnore() return } def sendTime = globalCorrMap.get(corrId) SampleResult.setTime(System.currentTimeMillis() - sendTime) SampleResult.setSuccessful(true) SampleResult.setResponseData(msg.getBody(String.class), "UTF-8") globalCorrMap.remove(corrId)
tearDown线程组JSR223元件(清理)
// 这里放你原有关闭MQ连接的代码 // 清空全局存储 props.remove("globalCorrMap")
内容的提问来源于stack exchange,提问作者JustNatural
相关产品推荐
相关产品推荐

