简介:本资源面向需要使用JMeter 3.3对RabbitMQ进行压力测试的测试工程师与后端开发人员,提供一套可直接运行的实战工具包。内容围绕JMeter非HTTP协议支持展开,涵盖AMQP Sampler等插件的集成、RabbitMQ连接参数配置、线程组并发模型设计以及聚合报告等监听器的结果分析,帮助读者快速搭建消息队列压测环境。压缩包共2000个文件,以1510个html、482个png、271个js等前端与文档资源为主,同时包含82个jar依赖、45个jmx测试脚本、37个xml配置及多种lang、properties文件,整体约51.92MB,目录结构完整,便于按模块查阅与二次修改。目前已有1089人学习下载,适合希望掌握JMeter扩展协议压测、理解RabbitMQ高并发性能表现的读者参考实践。
1. 当压测工具遇上消息队列:为什么要在 JMeter 3.3 里追加 RabbitMQ 压测
很多团队做性能测试时,HTTP 接口压得风生水起,一到消息队列就抓瞎。订单系统下单后异步写 RabbitMQ,你压 HTTP 只能测到“消息发出去了”,至于 Broker 扛不扛得住、消费端会不会积压、连接数会不会打满,全是黑匣子。JMeter 3.3 本身不带 AMQP 采样器,默认只能测 HTTP/JDBC 这类协议,想压 RabbitMQ 就得自己追加扩展。这件事的价值在于:把消息生产者和消费者的吞吐、延迟、错误率纳入同一套压测报告,而不是靠 Broker 自带的管理页面看个大概。适合谁?手里已经有 JMeter 3.3 压测体系、不想再引入第二套工具、又需要验证 RabbitMQ 在峰值下的表现的后端或测试工程师。下面从环境准备到参数调优,把这条路走通。
2. 环境准备与 AMQP 插件选型:JMeter 3.3 怎么接上 RabbitMQ
2.1 为什么选 AMQP 插件而不是自己写 Java Sampler
JMeter 3.3 的扩展机制支持两种方式:一种是写 Java Sampler 继承AbstractSampler,另一种是装现成的 AMQP 插件。自己写 Java Sampler 不是不行,但你要处理连接池、信道复用、消息确认、异常重连,代码量不小,而且压测脚本里没法灵活改参数。常见做法是直接用 AMQP 插件,它把连接配置、交换机、路由键、消息体都暴露成 JMeter 的 GUI 参数,改起来不用重新编译。
选型时注意版本匹配。JMeter 3.3 对应的是 Java 8 环境,AMQP 插件要选支持 RabbitMQ 3.x 协议的版本。插件本质上是把 RabbitMQ 的 Java Client 封装成 JMeter 的AbstractSampler,所以底层还是走 AMQP 0-9-1 协议。你不需要在 JMeter 里装 RabbitMQ 服务端,只需要保证压测机和 Broker 网络互通,端口 5672(AMQP)或 5671(TLS)开放。
提示:JMeter 3.3 的插件管理器和后续版本不一样,很多新插件不兼容。建议手动把插件 jar 包丢进
lib/ext目录,而不是依赖插件市场在线安装。
2.2 插件安装与目录结构确认
假设你已经解压了 JMeter 3.3 到某个目录,比如/opt/jmeter。AMQP 插件的核心 jar 包通常叫jmeter-amqp-x.x.x.jar,依赖amqp-client-x.x.x.jar。把这两个文件放进lib/ext,然后重启 JMeter。
# 进入 JMeter 安装目录 cd /opt/jmeter # 确认 lib/ext 下已有插件 jar ls -l lib/ext/ | grep -i amqp # 如果没有,手动拷贝(假设插件包已下载到当前目录) cp jmeter-amqp-*.jar lib/ext/ cp amqp-client-*.jar lib/ext/ # 重启 JMeter ./bin/jmeter.sh逻辑说明:lib/ext是 JMeter 加载扩展组件的标准路径,放进去后 JMeter 启动时会自动扫描。amqp-client是 RabbitMQ 官方 Java 客户端,插件依赖它来建立 TCP 连接和信道。参数上注意 jar 包版本要一致,比如插件用 4.0.0 版客户端,你就别混用 5.x 的客户端,否则运行时报NoSuchMethodError是家常便饭。
2.3 线程组与连接配置的最小闭环
装好插件后,在测试计划里添加线程组,再添加 AMQP 采样器。关键配置项有这几个:
| 配置项 | 含义 | 典型值 |
|---|---|---|
| Host | Broker 地址 | 192.168.1.100 |
| Port | AMQP 端口 | 5672 |
| Virtual Host | 虚拟主机 | / |
| Username | 用户名 | guest |
| Password | 密码 | guest |
| Queue | 目标队列名 | test.queue |
| Exchange | 交换机名 | test.exchange |
| Routing Key | 路由键 | test.key |
| Message | 消息体 | Hello JMeter |
先跑一个单线程、单循环的调试请求,确认能连上 Broker 并成功投递一条消息。如果这一步就报Connection refused,先查网络和防火墙;报ACCESS_REFUSED,查用户名密码和 vhost 权限。别急着上并发,最小闭环跑通再谈压测。
3. 压测脚本编排:从单条消息到持续吞吐
3.1 消息体参数化与 CSV 数据驱动
压测不能只发一条固定消息,否则 Broker 的磁盘写入和消费端处理逻辑都测不出真实差异。常见做法是用 CSV Data Set Config 把消息体参数化。准备一个messages.csv,每行一条消息内容,JMeter 逐行读取。
order_id,amount,status 1001,99.5,created 1002,150.0,paid 1003,200.0,shipped在 JMeter 里添加 CSV Data Set Config,文件名指向该 CSV,变量名写order_id,amount,status。然后在 AMQP 采样器的 Message 字段里用${order_id},${amount},${status}引用。这样每次请求发出去的消息体都不同,能避免 Broker 或消费端做重复消息优化导致压测结果虚高。
逻辑说明:CSV 文件默认是逗号分隔,如果消息体本身含逗号,要改分隔符或加引号。参数说明:Recycle on EOF设为 true 表示文件读完后循环,Stop thread on EOF设为 false,否则线程会提前结束。压测时长较长时建议把 CSV 行数准备足,比如 1 万行以上,避免循环读取带来的缓存效应。
3.2 线程组参数怎么设才不翻车
线程数、Ramp-up、循环次数这三个参数直接决定压测强度。新手常犯的错是一上来就 500 线程、Ramp-up 1 秒,结果 JMeter 自己先 OOM,或者 Broker 连接数瞬间打满触发告警。
我一般会这样起步:
- 线程数:50
- Ramp-up:10 秒
- 循环次数:永久,配合调度器跑 5 分钟
# 非 GUI 模式运行,便于观察日志和资源占用 ./bin/jmeter.sh -n -t rabbitmq_test.jmx -l result.jtl -e -o report/逻辑说明:-n表示非 GUI 模式,压测机资源消耗更低;-t指定测试计划文件;-l输出原始结果;-e -o生成 HTML 报告。参数上注意-l指定的文件如果已存在,JMeter 3.3 会直接报错,每次跑之前先删掉旧文件。Ramp-up 太短会导致连接风暴,RabbitMQ 的connection_created速率飙升,严重时触发connection_closed_abruptly。
3.3 断言与结果收集:怎么判断压测是否有效
光看吞吐量不够,还要加响应断言。AMQP 采样器支持检查响应是否包含特定字符串,但更可靠的是用 JSR223 断言判断消息是否发送成功。RabbitMQ 的 Java Client 在basicPublish后如果没有抛异常,通常认为消息已到达 Broker,但持久化消息还需要等确认。
// JSR223 断言示例:检查采样器是否成功 if (prev.isSuccessful()) { // 消息发送成功 AssertionResult.setFailure(false); } else { AssertionResult.setFailure(true); AssertionResult.setFailureMessage("AMQP 发送失败: " + prev.getResponseMessage()); }逻辑说明:prev是 JMeter 内置变量,代表上一个采样器的结果。isSuccessful()返回 false 时说明连接断开或信道异常。参数上注意 JSR223 断言要选 Groovy 语言,性能比 BeanShell 好。结果收集建议同时开聚合报告和用后端监听器写 InfluxDB,方便看趋势。
4. 避坑与排查:RabbitMQ 压测里最容易翻车的 5 个点
4.1 连接数暴涨导致 Broker 拒绝服务
现象:压测开始几秒后,JMeter 报Connection refused或SocketException,Broker 日志出现too many connections。
原因:每个 JMeter 线程默认创建独立连接,50 线程就是 50 个 TCP 连接。RabbitMQ 默认connection_max是 65535,但文件描述符限制可能更低,或者 Broker 配置了更小的上限。
解决:在 AMQP 采样器里启用连接复用,让多个线程共享一个连接。插件通常提供Use Connection Pool选项,勾选后设置池大小。另外检查 Broker 的ulimit -n,确保文件描述符足够。
4.2 消息持久化导致吞吐骤降
现象:不开启持久化时吞吐 5000 msg/s,开启后掉到 800 msg/s。
原因:持久化消息要写磁盘并等 fsync,磁盘 IO 成为瓶颈。RabbitMQ 的持久化包括队列持久化和消息投递模式delivery_mode=2。
解决:压测时明确目标。如果测的是极限吞吐,用非持久化;如果测的是可靠性场景,接受吞吐下降,但要把磁盘换成 SSD 或调整vm.dirty_ratio。别把两种场景混在一起测,否则数据没法解读。
4.3 信道未关闭导致内存泄漏
现象:压测跑 10 分钟后 JMeter 内存持续上涨,最终 OOM。
原因:每次采样都新建 Channel 但不关闭,Channel 对象在 Broker 端和客户端都占内存。
解决:在 AMQP 采样器里启用Close Channel选项,或者用 JSR223 在tearDown里统一关闭。更稳妥的做法是用连接池管理 Channel,复用而不是每次新建。
4.4 消息体过大触发帧拆分
现象:小消息压测正常,换成 1MB 大消息后大量超时。
原因:AMQP 协议有帧大小限制,默认frame_max是 131072 字节。大消息会被拆成多个帧,增加网络往返和 Broker 处理开销。
解决:调整 Broker 的frame_max参数,或者把消息体控制在 128KB 以内。压测大消息时降低并发数,观察网络带宽是否打满。
4.5 消费端缺失导致队列积压误判
现象:压测报告显示发送成功率 100%,但 Broker 管理页面队列消息数持续上涨。
原因:只压了生产者,没有消费者,消息全堆在队列里。队列深度过大时 Broker 会触发流控,反而限制生产者速率。
解决:压测方案里要么同时启动消费端,要么明确只测生产端并接受队列积压。如果测的是端到端延迟,必须部署消费者并统计消费耗时。
5. 进阶技巧:用常量吞吐量控制器逼近真实业务峰值
5.1 常量吞吐量控制器的参数含义
JMeter 的 Constant Throughput Timer 可以控制每分钟的请求数,单位是 samples per minute。把它挂在 AMQP 采样器下面,就能让压测按指定速率发送消息,而不是线程全速跑。
| 参数 | 含义 | 示例 |
|---|---|---|
| Target throughput | 目标吞吐量(每分钟) | 6000 |
| Calculate throughput based on | 计算基准 | this thread only / all active threads |
| Mode | 等待策略 | all active threads in current thread group |
假设你要模拟每分钟 6000 条消息的生产速率,把 Target throughput 设为 6000,模式选all active threads。这样 10 个线程会均分这个速率,每个线程每分钟发 600 条。
5.2 结合调度器做阶梯加压
真实业务峰值不是一瞬间到来的,而是逐步爬升。用线程组的调度器配合常量吞吐量控制器,可以做出阶梯效果。
# 第一段:50 线程跑 2 分钟 # 第二段:100 线程跑 2 分钟 # 第三段:200 线程跑 2 分钟 # 用多个线程组串联,每个线程组设不同的线程数和调度时长逻辑说明:JMeter 3.3 支持多个线程组顺序执行,把每个阶梯写成一个线程组,勾选Run Thread Groups consecutively。参数上注意每个线程组的 Ramp-up 要设合理,比如 100 线程用 20 秒爬升,避免瞬间冲击。
5.3 用后端监听器对接时序数据库
压测结果只存 JTL 文件不够直观,我习惯用 Backend Listener 把指标实时写到 InfluxDB,再用 Grafana 看板监控。JMeter 3.3 自带 InfluxDBBackendListenerClient,配置好 URL、数据库名、measurement 前缀即可。
<!-- 在 jmx 文件里添加 Backend Listener 节点 --> <BackendListener guiclass="BackendListenerGui" testclass="BackendListener" testname="InfluxDB Listener"> <elementProp name="arguments" elementType="Arguments"> <collectionProp name="Arguments.arguments"> <elementProp name="influxdbUrl" elementType="Argument"> <stringProp name="Argument.name">influxdbUrl</stringProp> <stringProp name="Argument.value">http://192.168.1.200:8086/write?db=jmeter</stringProp> </elementProp> <elementProp name="application" elementType="Argument"> <stringProp name="Argument.name">application</stringProp> <stringProp name="Argument.value">rabbitmq_pressure</stringProp> </elementProp> </collectionProp> </elementProp> </BackendListener>逻辑说明:influxdbUrl指向时序数据库的写入接口,application是标签名,方便在 Grafana 里按应用过滤。参数上注意 InfluxDB 的 retention policy 要提前建好,否则数据写入报错。压测过程中看 Grafana 的response_time和throughput曲线,能直观判断 Broker 在哪个并发点开始劣化。
5.4 一个我踩过的坑:时间同步问题
有一次压测结果里响应时间忽高忽低,排查半天发现是 JMeter 压测机和 RabbitMQ Broker 的时钟不同步,导致消息里的时间戳和 Broker 记录的时间对不上,误判为网络抖动。后来统一用 NTP 同步,数据才稳定。这个坑不常遇到,但一旦碰上,能让你怀疑人生。压测前花两分钟检查date命令输出,比事后翻日志划算得多。
希望帮到你。
本文还有配套的精品资源,点击获取