1. 为什么性能测试到第14篇才聊插件和服务器监控
做过几轮完整压测的人都清楚一个事实:JMeter 本身能跑通一个脚本,和能把一次压测做扎实,中间隔着一大截。前面十几篇里陆陆续续把线程组、断言、参数化、结果树这些东西拆完了,脚本能跑、报告能出,看起来任务完成了。但真正上到预发或者生产环境压一轮,问题就冒出来了——响应时间曲线一切正常,服务器 CPU 已经打满,可 JMeter 这边的汇总报告完全看不出来;数据库连接池爆了,应用日志里全是超时报错,压测报告却因为断言写得太松直接放行。这类"脚本层面没问题、系统层面炸了"的情况,十个压测项目里至少撞上七八个。
所以这一篇不再纠结单个组件的用法,而是把视角往上抬一层,聊两个决定压测质量上限的东西:一是常用插件,二是服务器资源监控。插件解决的是"JMeter 原生能力不够"的问题,比如原生线程组做不出阶梯式加压、原生监听器画不出像样的趋势图、原生断言处理不了复杂逻辑;服务器监控解决的是"只看客户端视角会误判"的问题,压测机观察到的响应时间只是请求往返的一小段,真正的瓶颈往往藏在被测服务器的 CPU、内存、磁盘 IO、网络和 JVM 里。把这两块补上,压测报告才从"能看"变成"敢拿给团队看"。
不管你是刚装完 JMeter、还在照着教程点按钮的新手,还是已经能独立写 BeanShell 断言、做数据库参数化取值的老手,这篇都值得过一遍。新手能拿到一条从插件安装到监控看板的完整路径,老手可以直接跳到插件选型对比和 Prometheus 那几段,看看有没有漏掉的细节。下面所有操作都是我在实际项目里反复跑过、踩过坑之后沉淀下来的,参数和目录结构尽量给到能直接照抄的程度,不玩虚的。
2. 插件体系的整体设计思路与选型逻辑
2.1 原生 JMeter 的能力边界在哪里
先把预期摆正,JMeter 原生功能并不是"弱",它只是"偏保守"。核心的 HTTP 采样器、线程组、断言、监听器都在,日常接口压测完全够用。它真正欠缺的是三类东西:第一类是加压策略的灵活性,原生线程组只能设置固定线程数、固定 Ramp-Up 时间,想要"每 30 秒加 20 个线程,加到 200 稳住 5 分钟再退"这种阶梯场景,靠原生配置基本做不出来;第二类是可视化能力,原生的聚合报告、查看结果树,一个是纯表格,一个是纯文本,压测过程中想实时看吞吐量曲线的走势,原生给不了;第三类是外围集成,比如从消息队列取数据、对接监控平台、生成更专业的 HTML 报告,这些都需要额外扩展。
插件本质上就是社区把这些缺口补齐的产物。它们遵循 JMeter 的扩展规范,编译成 jar 包丢进lib/ext目录,重启后就能像原生组件一样在界面上使用。理解了这一点,选插件就有了判断标准——这个插件是不是在补上面三类缺口之一,如果不是,那它大概率是可选项,装多了只会拖慢 JMeter 启动、增加版本冲突风险。
2.2 插件管理器的安装与依赖梳理
手动往lib/ext里丢 jar 包是上古做法,现在统一走Plugins Manager。它本身也是一个 jar,下载下来放进lib/ext,重启 JMeter,菜单栏的"选项"下面会多出一个"Plugins Manager"入口。之后的插件安装、升级、卸载全在这个界面里点,它会自动处理依赖关系和版本匹配,避免你装了一个插件结果因为缺依赖跑不起来。
安装路径需要留意两点。一是 JMeter 的安装目录不要带空格和中文,D:\tools\jmeter这种就挺好,D:\我的工具\性能测试\jmeter这种在某些插件加载时会出问题,路径解析异常;二是插件管理器本身有版本,和你的 JMeter 大版本要对上,JMeter 5.x 用对应版本的插件管理器,跨大版本混用会出现界面能打开但插件装完不生效的情况。安装完先别急着装一堆插件,先在插件管理器里点一下"Available Plugins",确认列表能正常拉取,这一步通了再往下走。
注意:公司内网环境如果拉不到插件列表,多半是网络策略问题,可以让运维把插件源地址加进白名单,或者在有外网的机器上把插件 jar 包下好,再拷进
lib/ext手动离线安装。
2.3 常用插件清单与各自解决的问题
插件市场里几十上百个组件,真正高频用到的其实就那么几个。我按"解决什么问题"来分类,比按字母顺序罗列实用得多。
| 插件名称 | 解决的核心问题 | 典型使用场景 | 优先级 |
|---|---|---|---|
| Custom Thread Groups | 提供阶梯、波浪、到达率等高级加压模型 | 模拟真实用户逐步涌入 | 高 |
| 3 Basic Graphs | 提供吞吐量、响应时间、活跃线程数实时曲线 | 压测过程实时观察趋势 | 高 |
| PerfMon (Servers Performance Monitoring) | 采集被测服务器 CPU、内存、磁盘、网络指标 | 客户端与服务端数据对齐 | 高 |
| JSON/YAML/XML 相关提取器 | 处理复杂响应结构的参数提取 | 接口关联、链路压测 | 中 |
| Dummy Sampler | 生成可控的假响应,调试脚本逻辑 | 脚本搭建阶段自测 | 中 |
| MQTT / Kafka 相关插件 | 压测消息队列类中间件 | 物联网、异步消息场景 | 按需 |
选插件的原则很直接:优先装能改变加压模型和监控能力的,其次装能提升脚本编写效率的。前两类直接决定压测结论的可信度,后一类只是让你的工作轻松一点。像 Dummy Sampler 这种,脚本调试阶段很香,但正式压测时用不上,属于"用完可以卸"的类型。
2.4 插件版本与 JMeter 大版本的匹配陷阱
这是新手最容易栽的地方。插件和 JMeter 之间存在版本耦合,某个插件在 5.3 上跑得好好的,升到 5.6 可能就报ClassNotFoundException或者界面元素直接消失。原因在于 JMeter 内部 API 偶有调整,插件如果没跟着更新,就会失配。
我的习惯是每个 JMeter 大版本对应一套固定插件版本,记录在项目文档里,不要看到插件管理器提示"有新版本"就随手升级。压测环境讲的是稳定可复现,不是追新。升级前先在测试环境跑一遍基准脚本,确认插件加载正常、报告结果一致,再动正式环境。踩过一次坑——某次手贱全量升级插件,结果 Custom Thread Groups 的界面渲染崩了,线程组配置打不开,排查了半天才发现是插件版本和 JMeter 不匹配,回退版本才恢复。
3. 核心插件实操与服务器监控落地要点
3.1 Custom Thread Groups 阶梯加压配置详解
原生线程组的痛点是加压过程生硬,一上来就是全部线程同时启动,对被测系统是"突然袭击",很容易触发限流或者直接把服务打挂,压出来的数据也不真实。Custom Thread Groups 提供的Stepping Thread Group和Concurrency Thread Group就是为了解决这个。
以 Stepping Thread Group 为例,配置项拆开看其实就几个关键参数:
- This group will start:总线程数,比如 200
- First, wait for:启动前的等待时间,通常设 0
- Then start:第一批启动的线程数,比如 20
- Next, add:每轮新增线程数,比如 20
- Threads every:每轮之间的间隔,比如 30 秒
- Using ramp-up:新增线程的爬坡时间,比如 10 秒
- Then hold load for:达到峰值后保持多久,比如 300 秒
- Finally, stop:结束时如何退线程,一般选 10 秒内全部停止
这套配置翻译成人话就是:从 20 个线程起,每隔 30 秒加 20 个,加到 200 为止,峰值稳住 5 分钟,然后收尾。真实的电商大促流量就是这个形态——逐步爬升、维持高峰、回落到常态。用这个模型压出来的 TPS 曲线才有参考价值,能看出系统在哪个并发区间开始劣化。
实操心得:Ramp-Up 时间不要设成 0,哪怕每个新批次只有 20 个线程,也给它 5 到 10 秒的爬坡期。原因是线程启动本身有开销,瞬时全部启动会在客户端制造毛刺,把本该属于服务端的压力表现混进压测机自身的抖动里,污染数据。
3.2 实时监控面板:3 Basic Graphs 的读图技巧
压测过程中最忌讳的是"蒙着眼睛跑"——跑完才看报告。3 Basic Graphs 插件提供三张实时图:Transactions per Second(吞吐量)、Response Times Over Time(响应时间趋势)、Active Threads Over Time(活跃线程数)。这三张图摆在一起看,能帮你判断压测是否健康。
健康的形态是:吞吐量随线程数上升而上升,到某个点开始放缓甚至走平;响应时间在线程数上升初期基本平稳,逼近瓶颈时开始抬头;活跃线程数按你设计的阶梯整齐攀升。一旦出现"线程数还在涨,吞吐量不涨反跌,响应时间陡然拉升",基本可以判定系统已经进入瓶颈,再往上加压只会制造更多超时,数据失去意义。
读图有个小技巧:把三张图的时间轴对齐着看。如果响应时间抬头的时刻,恰好对应线程数刚跨过某个阈值,那这个阈值就是系统当前的并发容量参考点。这个点在容量规划里非常值钱,比单纯的"最大 TPS 是多少"更有指导意义,因为它告诉你能安全支撑多少并发。
3.3 PerfMon 插件采集服务器资源的方法
PerfMon 分两部分:服务端跑一个ServerAgent,客户端装 PerfMon 监听器。ServerAgent 是个独立的 Java 程序,丢到被测服务器上启动即可,它默认监听 4444 端口,负责采集并回传指标。客户端这边在 JMeter 里加一个 PerfMon Metrics Collector 监听器,配置好服务器 IP、端口和要采集的指标,压测时就会同步记录。
ServerAgent 支持的指标分几大类:CPU(用户态、系统态、空闲、等待)、内存(物理内存、交换分区)、磁盘 IO(读写速率、队列长度)、网络(收发字节数)。采集粒度默认 1 秒一次,可以调,但不要调得太密,否则采样本身会消耗被测服务器的资源,变成"监控影响被测对象"的尴尬局面。
配置时容易踩的坑有两个。一个是防火墙,ServerAgent 的 4444 端口要在服务端放行,否则客户端一直连不上,监听器图标是灰色的;另一个是权限,某些系统下 ServerAgent 采集磁盘和网络指标需要更高权限,用普通用户跑会拿到空值或者 0,看起来像"服务器完全没负载",其实是采不到数据。这两个问题都不难解决,但不知道的话能卡半天。
注意:ServerAgent 和 JMeter 的 JMX 采集是两回事。ServerAgent 采的是操作系统层面的指标,JVM 内部指标(堆内存、GC 次数、线程数)需要通过 JMX 单独开启。做 Java 应用压测时,两个都要上,缺一个都看不全。
3.4 插件安装目录结构与生效验证
装完插件一定要验证是否真的生效,别想当然。验证方法很简单:重启 JMeter,新建一个测试计划,看右键菜单里能不能找到对应组件。找不到,说明 jar 没加载成功。
JMeter 的插件相关目录主要有三个:
lib/ext:存放插件核心 jar 和 JMeter 扩展组件,绝大多数插件装这里lib:存放插件依赖的第三方类库,插件管理器会自动往里放bin:存放启动脚本和配置文件,一般不动
手动排查加载失败时,先看jmeter.log,日志里会明确写出哪个 jar 加载失败、报了什么错。常见错误无非是版本不匹配、依赖缺失、jar 损坏三种。插件管理器安装的大概率没问题,手动拷进去的要特别留意。
4. 完整压测实操流程与监控数据对齐
4.1 从零搭建一个带监控的压测计划
把前面讲的东西串起来,走一遍完整流程。假设要压一个订单查询接口,目标并发 200,想看服务端资源消耗。
第一步,装插件。通过 Plugins Manager 装 Custom Thread Groups、3 Basic Graphs、PerfMon 三个,重启生效。第二步,起 ServerAgent。把它上传到被测服务器,解压后执行启动命令,看到它打印出"Started"之类的字样,说明端口已经在监听。第三步,建测试计划。加 HTTP 请求默认值配置服务器地址和端口,加 HTTP 采样器配置接口路径和参数,参数化的部分如果用 CSV 就加 CSV Data Set Config。第四步,换加阶梯线程组,按 3.1 的参数配好加压曲线。第五步,加监听器,把 PerfMon Metrics Collector 和三个实时图拉进来,PerfMon 里填服务器 IP、4444 端口,勾选 CPU、Memory、Disk IO。第六步,跑。
跑的过程中盯着实时图和服务端资源图看,两条曲线叠在一起,很容易看出转折点。等压测结束,PerfMon 采集的数据会存进结果文件,可以用它的图表工具离线画图,或者导出 CSV 做进一步分析。
4.2 参数化取值与数据库取数的注意点
压测脚本里参数化是绕不开的,尤其是需要真实用户数据的场景。常用的有三种方式:CSV 文件、数据库查询、函数生成。CSV 最简单,一个文件一列数据,CSV Data Set Config 引用即可;数据库方式需要加 JDBC Connection Configuration 和 JDBC Request,从库里捞数据存进变量,再用${变量名}引用。
数据库取数有两个坑要提前说。一是连接池配置,JMeter 里的 JDBC 连接池参数别设太小,压测线程多的时候如果池子不够,采样器会卡在等待连接上,报出一堆莫名其妙的超时,其实是脚本自身的问题不是服务端的问题。二是密码和字符集,数据库连接串里的字符集要和库一致,密码里如果有特殊字符要正确转义,不然连不上库,脚本直接挂掉。
还有个更隐蔽的问题:如果每个线程都要从数据库取一次数据,而数据库连接又没做好复用,压测本身会对数据库造成额外压力,污染被测结果。正确的做法是尽量在脚本初始化阶段一次性把数据捞进内存,压测过程中只做内存读取,避免把"压测机的数据库访问"混进被测系统的负载里。
实操心得:用 CSV 参数化时,文件里预留足够的数据行数,行数少于线程循环次数会导致数据被重复读取。JMeter 在文件读完后的行为取决于 Recycle on EOF 的设置,默认是循环重用,如果不希望重复,把它关掉并让线程在数据耗尽时停止。
4.3 客户端与服务端数据的对齐分析
压测最核心的分析动作,是把客户端和服务端两边的数据对起来看。JMeter 这边给你响应时间和 TPS,PerfMon 那边给服务端的资源曲线,两相对照才能定位瓶颈在哪。
举个常见的对照关系:
- 响应时间上升,同时服务端 CPU 打满 → 大概率是计算密集型瓶颈,代码里有热点
- 响应时间上升,CPU 不高,磁盘 IO 队列变长 → 大概率是磁盘瓶颈,日志写入或数据落盘拖累
- 响应时间上升,CPU 和磁盘都正常,但网络发送字节数飙升 → 可能是响应体太大,或者网络带宽成了瓶颈
- TPS 上不去,服务端各项资源都很闲 → 检查网络链路、中间件连接池、下游依赖,瓶颈可能在压测机到服务端之间,或者在某个被忽略的下游服务
这套对照逻辑是我做压测复盘时用得最多的,基本上看一眼资源图就能缩小排查范围。关键是资源指标要和压测阶段对齐——比如你 10 点整开始加压,资源图在 10 点 05 分才出现异常,那这个异常就要和你当时的线程数阶段对得上,不能错位解读。
4.4 压测结果报告与数据导出
压测跑完,结果文件默认是 JTL 格式。这个文件可以用聚合报告打开看汇总,但更好的做法是用命令行模式生成 HTML 报告,图表更专业,分享给团队也更直观。生成命令大致是这样:
jmeter -g result.jtl -o ./report_output-g指定结果文件,-o指定输出目录,目录必须为空,否则会报错。生成的报告里包含 TPS 曲线、响应时间分布、百分位统计、错误率等,比界面上的聚合报告详细得多。
如果只想要原始数据做二次分析,可以把 JTL 导成 CSV。查看结果树里的数据也能导出,但要注意大数据量情况下别开着查看结果树跑压测,它会把所有响应都存进内存,几万个请求下来能把 JMeter 自己拖死。正式压测时监听器只留必要的,查看结果树、查看结果树里的响应数据这类耗内存的组件,能关就关。
5. 常见问题与排查技巧实录
5.1 插件装了不生效怎么办
这是反馈最多的问题,按顺序排查基本都能解决。首先重启 JMeter,插件加载发生在启动阶段,不重启不生效。其次看jmeter.log,加载失败的 jar 会留明确记录。第三检查版本匹配,插件版本和 JMeter 大版本是否对应。第四确认目录放对,核心 jar 在lib/ext,依赖在lib。第五排除路径问题,JMeter 目录别带中文和空格。
还有一种情况是"看起来生效了但功能异常",比如界面出来了但一保存就报错。这多半是插件和 JMeter 之间存在 API 差异,插件没有完全适配当前版本。解决办法是找该插件对应 JMeter 版本的发行版,别硬用。
5.2 ServerAgent 连不上的排查路径
ServerAgent 连不上,表现是 PerfMon 监听器一直没数据、图标灰色。排查顺序:先确认 ServerAgent 进程真的在跑,再确认 4444 端口在服务端处于监听状态,然后从客户端用 telnet 试一下端口通不通,最后检查防火墙规则。这四步走下来,90% 的连不上问题都能定位。
如果是"能连上但某些指标是 0",那就是权限问题。磁盘 IO 和网络指标在某些系统下需要较高权限才能读取,换用有足够权限的账户启动 ServerAgent 即可。这个坑很隐蔽,因为 CPU 和内存采集是正常的,容易让人误以为一切正常,结果磁盘曲线一直贴地。
5.3 压测机自身成为瓶颈的判断
压测机资源不够是很典型的隐蔽问题。表现是:怎么加压,服务端的 TPS 都上不去,响应时间还越来越长,但服务端资源看着很闲。这时候要回头看看压测机自己的 CPU、内存、网络。JMeter 是偏重量级的压测工具,线程数上了几百,加上各种监听器,压测机可能先扛不住。
判断方法:在压测机上装个监控工具(甚至就是任务管理器),看压测过程中压测机的 CPU 和网络使用率。如果压测机 CPU 长期 90% 以上,或者网络出口带宽跑满,那瓶颈很可能在压测机这边。解决办法要么用分布式压测,master 加多台 slave 分担压力,要么优化脚本,减少不必要的监听器和断言开销,把压测机的资源留给真正发请求这件事。
5.4 BeanShell 断言的性能陷阱
BeanShell 断言很灵活,能写任意逻辑,但它是解释执行的,性能开销不小。在几百上千线程的高并发压测里,每个请求都跑一遍 BeanShell,JMeter 自己的 CPU 会被吃掉一大块。写断言时优先用原生断言(响应断言、JSON 断言),非要用脚本逻辑再考虑 JSH 或者 Groovy,Groovy 的性能比 BeanShell 好不少,语法也更现代。
如果确实必须用 BeanShell,尽量把逻辑写简单,别在里面做复杂字符串处理或者调外部接口。还有个技巧是把部分校验逻辑前移到采样器本身,用正则提取器先把关键字段提取出来,再在断言里做简单比较,别在断言里做提取。
5.5 问题速查表
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| 插件界面找不到组件 | jar 未加载或版本不匹配 | 查 jmeter.log,核对版本 |
| ServerAgent 图标灰色 | 端口不通或进程未启动 | telnet 4444,查防火墙 |
| 部分服务器指标为 0 | 采集权限不足 | 提权启动 ServerAgent |
| 服务端资源闲但 TPS 上不去 | 压测机瓶颈或下游阻塞 | 查压测机资源,排查依赖服务 |
| 响应时间高但 CPU 不高 | 磁盘或网络瓶颈 | 看磁盘 IO、网络发送量 |
| 压测结果文件异常大 | 监听器存了太多响应数据 | 关闭查看结果树等重组件 |
| 数据库参数化超时 | 连接池配置过小 | 调大 JDBC 连接池 |
| BeanShell 断言拖慢压测 | 脚本解释执行开销 | 换 Groovy 或原生断言 |
5.6 几个我踩过的坑
说几个不太常见但很耗时间的坑。第一个是HTTPS 证书,压测 HTTPS 接口时如果服务端用了自签证书,JMeter 默认会校验失败。解决办法是在jmeter.properties里配置信任所有证书,或者把证书导入 JMeter 的 truststore。这个不配的话,所有请求都会报 SSL 相关错误,看起来像是接口挂了,其实是客户端不信任服务端。
第二个是录制脚本的过滤,用录制功能抓 HTTPS 流量时,浏览器里一大堆静态资源请求会混进来,必须配好 URL 过滤规则,只保留目标接口。不过滤的话脚本里几百个采样器,真正要压的接口就一两个,其他全是噪音。
第三个是上传文件场景,压测文件上传接口要注意勾选"对 POST 使用 multipart/form-data"并且正确配置文件参数,MIME 类型也要对,否则服务端收到的是空文件或者直接拒绝。Excel 上传和图片上传的 MIME 还不一样。
第四个是结果树的导出,有人压测完想从结果树里导出数据来分析,大数据量下这个操作会非常慢甚至卡死,正确做法是从 JTL 文件直接处理,或者在命令行模式用工具转换,别在界面里点导出。
6. 关于这套组合我自己的一些体会
插件和服务器监控这两块,说白了是把 JMeter 从一个"发请求的工具"变成"能出结论的测试平台"的关键。我见过太多人脚本写得很漂亮,参数化、断言样样齐全,但报告拿出来没人信,问题就出在只看客户端数据、没有任何服务端资源佐证。加上 PerfMon 之后,报告里能同时给出"200 并发下 TPS 是这些、此时服务端 CPU 是这些、磁盘队列是这些",这样的数据才经得起追问。
一个我个人觉得比较实用的习惯:每次正式压测前,先跑一轮低并发(比如目标值的 10%)做基线,把服务端各项指标的正常区间记下来。正式压测时如果某个资源指标明显偏出基线范围,就说明这个指标可能在往瓶颈方向走,哪怕响应时间当时还没抬头,也能提前预警。这个小动作花不了几分钟,但对定位问题的帮助很大。
插件别贪多,前面说的三类缺口对应的插件装齐就够了。装得越多,启动越慢,版本冲突的风险越大,而且在团队协作时,每个人的 JMeter 环境越不一致,复现问题就越难。把插件版本固定下来写进项目文档,新同事接手时按文档装一遍,环境就对齐了。这个习惯看起来不起眼,但能省掉大量"我这里跑得好好的""你装了什么插件"的扯皮时间。
至于后续还能怎么扩展,如果团队已经有 Prometheus 这类监控平台,其实可以不完全依赖 PerfMon,直接在压测时用平台的看板看服务端指标,数据维度还更丰富。JMeter 负责产生压力,监控平台负责观察,两边按时间轴对齐看,效果一样好甚至更好。这套思路在容器化环境里尤其顺手,因为容器里的指标本身就通过 standard exporter 暴露出来,采集成本比在每台机器上跑 ServerAgent 低得多。