
简介《apache-jmeter-rabbitMQ测试》是一份面向性能测试工程师和运维开发者的RabbitMQ消息队列压力测试资源包。它基于Apache JMeter构建将完整测试工具链与消息中间件验证场景集于一身适合衡量生产者发送速率、消费者吞吐量及不同负载下的队列响应表现。压缩包共含2881个文件约53.02MB以1510个html结果报告、482个png指标截图、55个jmx测试计划为核心辅以82个jar插件依赖、48个txt参数说明和40个json配置文件可支撑测试计划回放与结果复盘。jmx脚本覆盖RabbitMQ生产者与消费者常见压测拓扑BeanShell扩展脚本提供自定义断言与动态参数处理能力调整连接参数即可复现测试。目前已有1854人学习使用适合需要快速搭建消息队列性能验证环境的中高级测试人员按说明配置交换机和队列参数即可运行并输出可视化报告。1. 用JMeter给RabbitMQ做压测这个zip包里装的就是一条完整的验证路径做过消息中间件性能验证的人多半经历过这种尴尬业务方问“RabbitMQ扛得住多大并发”你手里却只有生产者的测试代码和一份写得不全的配置说明。真要压测时要么临时拼脚本要么直接拿业务流量去试风险全靠运气。apache-jmeter-rabbitMQ测试.zip这个工具包解决的就是这件事——用JMeter这把成熟的压测工具把RabbitMQ的生产、消费、吞吐、延迟全部变成可视化数据顺带把交换器类型、路由键、消息持久化的参数组合也一并验证掉。它适合两类人一类是刚接手消息中间件、想搞清楚不同交换器模式对吞吐影响的测试工程师另一类是正在做技术选型、需要一组可复现的对比数据来支撑决策的开发者。整条链路不复杂——JMeter里装好AMQP插件配置好连接工厂、交换器、队列、生产者和消费者线程组跑一轮压测从聚合报告和后台管理API里读结果就能定位瓶颈。好消息是这套方案完全离线可用zip解压后插件、脚本和依赖都在本地不需要额外联网装包。我先把话说在前头JMeter测RabbitMQ分层很清楚——JVM参数决定客户端能开多少连接AMQP协议的channel复用决定吞吐上限而真正让你怀疑人生的往往不是插件本身而是路由键写错导致消息全部进了默认队列或者消费者线程数没调够造成消息积压。这些坑下面都会一步步拆开讲。2. 拆开压测方案AMQP协议在JMeter里是怎么被模拟成生产与消费的2.1 先搞明白JMeter凭什么能压RabbitMQJMeter本身不直接认识RabbitMQ它靠的是AMQP协议采样器——本质上是把Java客户端库的API调用封装成了Sampler接口。你在JMeter里配置的连接工厂、交换器、队列声明最终都会转成对Channel对象的调用。这意味着一个核心概念JMeter只是壳真正的压测能力由底层RabbitMQ Java Client决定。所以调整线程数、消息大小、确认模式这些参数时你其实是在调客户端库的行为而不是JMeter本身的线程调度。这对压测方案设计有两个直接影响。第一JMeter线程组里的“线程数”不等于RabbitMQ的连接数因为AMQP协议允许多个channel复用一个TCP连接而连接数过多会触发服务端的连接数上限得不偿失。第二消息的可靠性和吞吐是跷跷板——开启 publisher confirms生产者确认时每条消息都要等服务端回执吞吐明显下降关掉确认又可能丢消息。所以压测之前必须先定清楚这次验证的指标优先级。我一般会先画一张图发送端线程组里每个线程持有自己的Channel通过QueueingConsumer或异步回调接收确认消费端线程组则相反每个线程从共享队列里取消息。两层之间通过RabbitMQ集群解耦。压测过程中JMeter聚合报告记录的只是生产者发送耗时或消费者处理耗时整条链路的真实吞吐要看RabbitMQ管理API里的队列指标两边数据要拼起来看才完整。2.2 安装AMQP采样器从zip到插件目录的落地步骤很多第一次接触的人会卡在插件安装上。这个zip里已经内置了插件目录但如果你是从社区版JMeter起步就需要知道标准挂载方式。常见做法是把amqp-jmeter插件jar包jmeter-amqp-client-plugin或类似产物放进JMeter安装目录的lib/ext子目录然后重启JMeter。顺便检查两个前置依赖JMeter版本建议3.3以上RabbitMQ Java Client的jar包要和插件配套通常插件包已经带上了它依赖的客户端库。# 假设JMeter安装在 /opt/jmeter 下插件包已经准备好 # 步骤1检查lib/ext目录里有没有旧的AMQP插件有就先移除避免版本冲突 ls /opt/jmeter/lib/ext/ | grep -i amqp # 步骤2把jar包拷贝到lib/ext cp jmeter-amqp-client-plugin.jar /opt/jmeter/lib/ext/ # 步骤3确认RabbitMQ Java client也在依赖路径里 ls /opt/jmeter/lib/ | grep -i rabbit # 步骤4重启JMeter命令行启动可以看到插件加载日志 /opt/jmeter/bin/jmeter -n -t /dev/null -j /tmp/jmeter_check.log安装完成后打开JMeter图形界面新建测试计划右键添加Sampler时如果能看到AMQP Publisher和AMQP Consumer两个采样器说明插件被成功加载了。这一步失败时九成是jar包版本冲突把lib和lib/ext下所有旧版amqp相关文件清掉再重试就能解决。注意插件在启动时会对RabbitMQ Java Client做版本校验版本不匹配会直接抛NoSuchMethodError日志里看到这个字样时就该怀疑依赖冲突了。2.3 三个交换器类型对应三个压测场景直连、路由、通配符主题模式RabbitMQ的交换器类型直接决定消息分发路径也就决定了压测脚本设计。最常见的就是直连模式、路由模式、通配符主题模式。直连模式最简单队列绑定到交换器时指定一个固定的路由键生产者发送消息时带上完全相同的路由键消息就稳稳进了这个队列。压测时适合观察单队列的极限吞吐——生产者线程数从10加到200看聚合报告里Throughput曲线的拐点在哪。路由模式是对直连模式的扩展交换器下绑定多个队列每个队列绑定不同路由键生产者根据业务标识选择路由键。压测时要重点验证路由键的分布是否均匀——如果压测脚本里路由键写成了固定值所有消息会涌进同一个队列其他队列空转数据看起来像“系统吞吐很高”实际上另外几个队列根本没吃到流量。通配符主题模式最灵活也最容易踩坑绑定关系里用 * 号匹配一个单词、# 号匹配零个或多个单词。比如绑定键写order.#能接住order.created和order.cancelled.partial而order.*只能接住order.created。压测脚本里如果主题模式的绑定键配错了层级消息会绕到意想不到的队列里排查起来非常费时间。// 以JMeter的JSR223 Sampler为例用Groovy动态声明交换器和绑定 // 这种方式适合需要临时验证某种路由策略的场景 import com.rabbitmq.client.* def connFactory new ConnectionFactory() connFactory.setUri(amqp://guest:guestlocalhost:5672/%2f) def conn connFactory.newConnection() def channel conn.createChannel() // 声明topic类型交换器第四个参数true表示持久化 channel.exchangeDeclare(demo.topic, topic, true) // 分别验证 # 和 * 匹配行为 channel.queueDeclare(queue.hash, true, false, false, null) channel.queueDeclare(queue.star, true, false, false, null) channel.queueBind(queue.hash, demo.topic, order.#) channel.queueBind(queue.star, demo.topic, order.*) // 发一条多层级路由键验证两个队列都能收到 channel.basicPublish(demo.topic, order.created.v2, null, payload.getBytes()) channel.close() conn.close()这段脚本的意图是验证通配符主题模式对多层级路由键的匹配差异。关键参数是queueBind里的绑定键——order.#接收所有以order开头的多层级键order.*只接收刚好一个中间层级。压测前的脚本自检阶段建议跑一遍类似逻辑先确认消息落到了预期的队列里再去开高并发否则后面数据全是错的。3. 搭建RabbitMQ压测计划从连接配置到聚合报告看板3.1 连接工厂配置参数连接超时、心跳、自动恢复的合理值连接工厂是压测脚本的地基。JMeter的AMQP Sampler里能直接配URI、连接超时、心跳间隔和自动恢复开关。这几项参数对压测结果的真实性和稳定性影响比想象中大得多。连接超时的设置要参考RabbitMQ服务端的TCP backlog配置。超时设太短压测刚开始时大量线程同时建立连接会触发部分失败你会误判成服务端瓶颈超时设太长连接建立失败时JMeter线程会长时间阻塞导致聚合报告里的Sample Time虚高。合理做法是先做一次低并发冒烟测试比如50线程跑30秒看连接建立的平均耗时再把超时时间设成平均耗时的2倍。心跳间隔的作用是维持连接活性但它和压测有个互相干扰的点心跳包本身要占带宽高吞吐压测时机票网络可能因为心跳包和消息流量竞争导致延迟抖动。我一般会把心跳从默认的60秒拉长到300秒前提是网络环境没有NAT超时的问题。自动恢复开关建议压测时关掉——否则网络抖动时客户端会悄悄重连重连期间消息发送失败被吞掉报表上看不到任何异常数据的可信度就没了。# 连接工厂参数的推荐起点按实际环境微调 # uri格式amqp://用户名:密码主机:端口/vhost amqp.uriamqp://guest:guest127.0.0.1:5672/%2f amqp.connectionTimeout3000 amqp.handshakeTimeout10000 amqp.requestedHeartbeat300 amqp.automaticRecoveryEnabledfalse这里的关键认知是连接超时和握手超时是两个不同的阶段。连接超时管的是TCP建连握手超时管的是AMQP协议层的Connection.Start/StartOk交换。有些压测环境里TCP能连上但握手超时说明服务端负载过高或vhost权限校验卡顿这两个参数要分开看日志才能定位。3.2 生产者线程组把消息大小、发送间隔和确认模式做成梯度生产者压力要从三个维度去设计梯度线程数、消息大小、确认模式。线程数决定并发度消息大小决定网络和存储的压力特征确认模式决定可靠性和吞吐的取舍。// 生产者Sampler的JSR223脚本支持从CSV读取消息体方便做消息大小梯度 import com.rabbitmq.client.* def factory new ConnectionFactory() def uri new URI(vars.get(AMQP_URI)) factory.setUri(uri) // 读CSV里的messageSize字段构造不同规格的负载 def bodySize Integer.parseInt(vars.get(messageSize)) byte[] payload new byte[bodySize] new Random().nextBytes(payload) // 关键参数mandatorytrue时消息路由不到队列会return给生产者便于发现路由配置错误 def mandatory Boolean.parseBoolean(vars.get(mandatoryFlag)) channel.basicPublish(exchangeName, routingKey, mandatory, MessageProperties.PERSISTENT_TEXT_PLAIN, payload)生产者脚本里的MessageProperties.PERSISTENT_TEXT_PLAIN是必须注意的——它把消息标记为持久化持久化消息要落盘才能确认吞吐会明显低于非持久化消息。做梯度压测时先跑非持久化看网络和CPU瓶颈再跑持久化对比落盘开销这个对比数据基本就是写入磁盘性能的上限参考。消息大小的梯度我常用的序列是1KB、10KB、100KB、500KB。小于1KB时吞吐受限于消息条数而非字节数瓶颈在网络帧处理大于500KB时吞吐受限于带宽和磁盘写速率。每个梯度跑5分钟中间休息1分钟让队列排空避免上一轮积压的消息干扰下一轮的数字。3.3 消费者线程组与QoSprefetch_count不是越大越好消费者的压测设计比生产者更讲究核心参数是channel.basicQos里的prefetchCount——它决定一个消费者通道上最多允许未确认的消息数。设成0表示不限制消息会尽量塞给消费者但这容易导致内存暴涨设成1表示一次只处理一条吞吐受限但每条消息都处理完才取下一条。// 消费者Sampler的JSR223脚本核心片段 import com.rabbitmq.client.* def factory new ConnectionFactory() factory.setUri(new URI(vars.get(AMQP_URI))) def conn factory.newConnection() def channel conn.createChannel() // 关键参数prefetchCount设为100让消费者批量处理 channel.basicQos(100) def consumer new DefaultConsumer(channel) { void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) { // 模拟业务处理耗时可调整sleep时间观察吞吐变化 sleep(Integer.parseInt(vars.get(processTime))) channel.basicAck(envelope.deliveryTag, false) } } channel.basicConsume(queueName, false, consumer)prefetchCount的合理区间要按单条消息处理耗时来估算。如果每条消息处理耗时2毫秒prefetch设100等于给这个消费者准备了200毫秒的缓冲网络抖动时不至于等消息等到空闲但设成1000时消费者内存里积压的未确认消息体积可能超过堆内存限额触发GC压力增大反而拖慢处理速度。经验法则是prefetchCount乘以平均消息大小再乘以消费者线程数结果控制在堆内存的1/4以内。消费者线程组的线程数建议等于或略大于队列分区数。RabbitMQ的队列在单机上其实没有分区概念多个消费者共享一个队列时会均分消息但如果一个消费者处理慢其他消费者不会帮它分担已经取走但还没确认的消息。所以观察聚合报告时如果出现某个消费者线程的平均耗时明显偏高原因多半是prefetch太大导致消息分配不平衡。3.4 运行一次最小压测命令行跑通并导出CSV图形界面跑压测适合调试真正要拿数据得要命令行方式跑方便定时触发和后续自动化。最小可用的命令行压测命令如下测试计划文件里已经配好了线程数、循环次数和监听器。# 命令行压测-n表示非GUI模式-t指定脚本-l输出结果到CSV # -J参数可以动态覆盖脚本里的变量适合批量跑不同梯度 /opt/jmeter/bin/jmeter -n \ -t rabbitmq_pressure.jmx \ -l /tmp/result_$(date %s).csv \ -Jthreads100 \ -Jloop1000 \ -JmessageSize1024 \ -e -o /tmp/report_$(date %s)这个命令里的-J参数直接改了线程数和循环次数不用每次改jmx文件。跑完之后-e参数生成HTML报告-o指定输出目录。但注意JMeter聚合报告统计的Throughput是采样器级别的发送/接收速率不代表RabbitMQ实际处理速率——生产者发出去的消息可能还在队列里排队消费者还没拿到手。所以每次压测结束后要去RabbitMQ管理界面截一张队列深度图确认结束时队列里的消息数回到基线数据才算闭环。4. RabbitMQ压测最常见的5个坑从连接爆掉到消息积压排查4.1 连接数暴涨把RabbitMQ打挂channel复用才是默认姿势现象压测并发从50提升到200时RabbitMQ的Connection数跟着线性涨到200服务端日志开始报connection limit exceeded部分线程直接发消息失败。原因JMeter的AMQP Sampler默认行为里每个线程组线程各自创建自己的Connection而不是共享一个连接里的多个channel。RabbitMQ默认连接数上限通常在1000左右压测一开大就撞墙。解决改成显式控制连接池。在测试计划里用setUp线程组预先创建若干个共享Connection然后生产者线程通过一个全局持有的channel数组去取通道。具体做法是用JSR223 Sampler和__setProperty函数把Connection存到JMeter全局属性里所有生产者线程共用。如果插件不支持共享连接就限把线程组线程数压到50以内靠循环次数补偿总消息量效果差不多但连接数可控。4.2 路由键写错导致消息全部进默认队列压测报告一片绿灯现象压测跑了10分钟聚合报告吞吐很稳定但去管理界面看业务队列的深度始终为0反而默认队列amq.rapid或未绑定队列里堆了几十万条消息。原因交换器类型和绑定键配置不一致。比如交换器声明为topic类型绑定键写成order.*生产者发送时路由键写成order.created.v2——三级键不会被order.*匹配到。更隐蔽的情况是生产者Sampler里交换器名拼写错误消息发到了一个不存在的交换器RabbitMQ默认直接丢弃mandatoryfalse时甚至不会报错。解决压测前做一次消息追踪验证。用管理界面的Queue页面查看队列绑定关系再用一个单独的生产者脚本发10条不同路由键的消息逐个确认落点。还有一种土办法压测脚本里把mandatory设为true路由失败的消息会被basic.return回传给客户端在JMeter日志里能直接看到未送达的路由键。4.3 prefetch_count设成0导致消费端内存溢出现象消费者线程组压测刚开始时吞吐很高3分钟后GC频繁紧接着消费端JVM抛OOM压测自动停止。原因prefetchCount设成了0表示不限制RabbitMQ客户端会尽可能多地从队列拉消息到本地缓存。消息体很大的场景比如100KB几个消费者线程就能把堆内存塞满。解决要么按消息大小和堆内存的计算公式重新设prefetch要么把消息体改小。我一般用这个估算堆内存2GB单消息100KB预留1/4堆做缓存prefetch 512MB / 100KB ≈ 5000听起来很大但安全如果消息体是1MBprefetch只能设500左右。压测时观察管理界面的消费者详情页有个Unacked列那个数字接近prefetch乘消费者数时说明拉取饱和了调低prefetch观察是否影响吞吐。找到临界点后固定下来。4.4 持久化消息压测比预期慢10倍确认磁盘刷盘机制现象相同的并发和消息大小把MessageProperties从非持久化改成持久化后吞吐直接从每秒5000掉到每秒400甚至更低。原因持久化消息每次publish都要等消息落盘后返回确认。RabbitMQ的默认持久化策略是每个队列依次刷盘再做确认磁盘写延迟直接进链路。机械盘或云盘IOPS不够时这个瓶颈会被放大得很厉害。解决分两层看数据。第一层先测非持久化的纯吞吐能力这是网络和CPU的上限参考第二层测持久化时把并发降到20到50让磁盘队列堆起来而不是让线程干等确认。如果业务允许批量刷盘可以考虑BatchingRabbitMQPublisher之类的方式把多条消息攒一次刷盘吞吐能提升不少但这属于对客户端行为的修改要在压测报告里单独标注。4.5 队列消息积压但消费者线程空闲确认回执没开对现象压测结束后管理界面显示队列深度还有几千条消息消费者线程却已经全空闲了聚合报告里消费端吞吐和发送端吞吐差了一大截。原因消费者脚本里没有调用basicAck确认消息或者采样器配置了autoAckfalse但脚本没有在handleDelivery里发送确认。RabbitMQ把消息投递给消费者后如果消费者不确认消息会一直处于unacked状态队列深度不减。解决检查消费者的DefaultConsumer回调里是否调用了channel.basicAck。漏确认的直接后果就是消息在unacked状态卡死通道关闭后消息会自动回到队列重新投递。更隐蔽的情况是确认逻辑里pos参数写错——multiple标志设成true时确认了一批消息如果中间有一条处理失败重投队列的粒度就失控了。压测脚本里我用单条确认multiple保持false牺牲一点性能换明确的语义。5. 收数据看报表把JMeter聚合报告和RabbitMQ指标对齐的验证方法5.1 聚合报告里哪几个字段能信哪几个不能信JMeter聚合报告跑完后字段很多但直接对着RabbitMQ环境解读时要小心。Throughput和Average是采样器视角的数据分别表示每秒请求数和平均响应时间它们是JMeter线程发出请求到收到回执的耗时。这跟RabbitMQ服务端的处理吞吐是两码事——很可能JMeter已经显示Throughput 5000服务端队列里还积压着一堆没被消费的消息那个5000只是“发出去”的速率。能信的是这几个Error%表示发送或接收失败的比例这个字段要盯紧压测过程中一旦出现非零错误率整轮数据就作废了先排查原因再说95th pct这个百分位响应时间比Average更抗噪声压测时偶发GC暂停会让Average偏高95th能过滤掉一部分毛刺Received KB/sec和Sent KB/sec是网络层面的流量统计用这个字段能看出来消息体大小是否和配置一致——如果配置了100KB消息但Sent只有1MB/s得确认是否真的在发大包。不能直接信的是Samples这个字段在循环次数很大时会撑到百万级跟队列深度和消费者Lag对照才有意义Min和Max两极值基本没参考价值除非你怀疑有极端超时。5.2 RabbitMQ管理API和监控指标队列深度、消费速率、连接数JMeter报表只能代表施压方的视角RabbitMQ服务的真实状态必须从管理API拉数据来对齐。用RabbitMQ的HTTP管理接口可以直接拿到JSON格式的队列指标配合curl脚本或者JMeter的HTTP采样器都能做。# 拉取所有队列的实时指标需要management插件开启 curl -s -u guest:guest http://127.0.0.1:15672/api/queues?columnsname,messages,messages_unacknowledged,message_stats.publish_details.rate,message_stats.deliver_get_details.rate | python3 -m json.tool这段curl里的columns参数是关键——只取了队列名、消息总数、未确认数、发布速率和消费速率。压测时每10秒拉一次把数据记录下来结束时画一条队列深度随时间变化的曲线。如果深度曲线在压测进行中持续走高说明消费速率小于生产速率这时候JMeter聚合报告里做得再漂亮也没有意义压测结论应该是“生产者性能达标但消费者处理不过来”。对齐方法我给一个固定动作压测结束后取最后一分钟JMeter的Throughput和RabbitMQ的publish_details.rate做对比误差在5%以内说明数据是对得上的再取消费者deliver_get_details.rate和队列深度变化量对比确认积压量等于发布量减消费量的积分。这一步做完压测报告才有说服力。5.3 用Grafana或命令行二次验证把压测结果复现成趋势图压测数据是一次性的但性能验证需要趋势图才能看出拐点。常见做法是把JMeter生成的CSV塞进Grafana或者直接用RabbitMQ自带的管理图表看实时曲线。如果只是临时验证命令行脚本也能满足要求。# 用Python脚本从管理API拉数据并绘制简单趋势 import requests import json import time import csv from datetime import datetime base_url http://127.0.0.1:15672/api/queues auth (guest, guest) with open(rabbitmq_metrics.csv, w, newline) as f: writer csv.writer(f) writer.writerow([timestamp, queue_depth, publish_rate, consume_rate]) for _ in range(60): resp requests.get(base_url, authauth, params{columns: name,messages,messages_unacknowledged,message_stats.publish_details.rate,message_stats.deliver_get_details.rate}) data resp.json() # 取第一个业务队列的数据 q data[0] writer.writerow([datetime.now().isoformat(), q.get(messages, 0), q.get(message_stats, {}).get(publish_details, {}).get(rate, 0), q.get(message_stats, {}).get(deliver_get_details, {}).get(rate, 0)]) time.sleep(10)这个脚本60次采样拉10分钟的数据。关键点是采样间隔要覆盖压测的全过程压测结束后继续拉到队列深度回到0为止。如果队列深度长时间不回落说明消息积压成了持久状态要回去看消费者线程和基本参数。这套CSV数据配合Excel就能画图够用。5.4 对比测试的变量控制固定消息大小和确认模式才能比对比测试最怕变量失控。想比较直连模式、路由模式、通配符主题模式三种交换器的吞吐差异时如果每轮压测的消息大小、消费者线程数、确认模式都不一样对比出来的差异完全没有意义。我常用的对比矩阵如下表每轮只改交换器类型和路由键其他参数全部固定对比轮次交换器类型路由键/绑定键消息大小生产者线程prefetch持久化基线directorder.create1KB100100否Atopicorder.#1KB100100否Bfanout无需绑定1KB100100否Cdirectorder.create10KB100100否这个表的逻辑是先在固定消息大小下对比交换器类型再在固定交换器类型下对比消息大小。最终报告里要写清楚每个变量的控制方式别人拿到这个压测脚本才能复现出接近的结果。最忌讳的是压测一轮改三个参数翻车了都不知道是哪个变量拖累的。6. 进阶玩法用JMeter脚本参数化跑大规模压测并验证消息零丢失压测做到能跑出数据只是第一步真正有价值的验证是组合场景——生产者和消费者同时跑一端压满另一端观察是否积压最终确认消息零丢失。这个验证直接在JMeter的测试计划里加并行线程组就能做不需要额外写测试代码。具体做法是测试计划里放两个线程组生产者和消费者同时启动。生产者线程组用固定吞吐量定时器Constant Throughput Timer限制发送速率消费者线程组用持续循环模式一直消费。跑完后对比两个数字生产者线程组发送成功的消息总数和管理界面里消费者deliver_get消息总数加上队列里残留消息数之和。相等就说明零丢失。// 在tearDown线程组里校验消息计数从管理API读取最终队列深度 import java.net.* import java.io.* def url new URL(http://127.0.0.1:15672/api/queues/%2f/demo.queue) def conn url.openConnection() conn.setRequestProperty(Authorization, Basic guest:guest.getBytes().encodeBase64()) def json new groovy.json.JsonSlurper().parseText(conn.content.text) // 队列深度为0且消费计数等于生产计数才算通过 log.info(queue_depth json.messages) if (json.messages 0) { log.warn(验证失败队列仍有残留消息) } else { log.info(验证通过消息全部消费完成) }这段校验脚本的关键点是必须在生产者和消费者线程组都完全跑完后执行tearDown线程组正好符合这个时机。json.messages字段读的是队列当前的积压数如果大于0就要去查原因。注意管理API里的队列名如果带斜杠前缀需要URL编码写成%2f比较保险。消息零丢失验证之外还有一个值得试的进阶方向把压测脚本变成参数化模板用JMeter属性文件承载环境差异。团队里每个人的RabbitMQ地址可能不同把uri、队列名、交换器名统统抽成属性一份jmx脚本在开发、测试、生产三套环境里都能跑只是启动时用不同的-J参数。# 不同环境用同一份脚本只通过属性区分 /opt/jmeter/bin/jmeter -n -t rabbitmq_pressure.jmx \ -JAMQP_URIamqp://user:pass10.0.0.5:5672/%2f \ -JEXCHANGEorder.business \ -JQUEUEorder.pressure \ -JROUTING_KEYorder.create \ -l /tmp/env_prod_result.csv属性化的设计让压测方案具有了可复用性后续业务方要复测时不用重新学习脚本逻辑。做完整参数化之后我养成了一个习惯每次压测前三分钟先跑一个10线程的冒烟版本确认路由键、交换器、队列全部正常然后才放开并发跑正式数据。这十分钟的提前量救过我很多次——大多数翻车都不是并发问题而是前面的简单配置错了。希望帮到你。本文还有配套的精品资源点击获取