ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

JMeter插件与服务器监控实战:PerfMon与性能瓶颈定位

JMeter插件与服务器监控实战:PerfMon与性能瓶颈定位 1. 先把插件和服务器监控这两件事的关系捋顺1.1 原生 JMeter 在真实项目里到底卡在哪JMeter 装完打开新建线程组、加个 HTTP 请求、挂个聚合报告跑起来看着挺像那么回事。可真接到一个上线前的性能验证任务这套原生组合很快就不够用了。第一次让我意识到问题是一次接口压测客户端曲线显示平均响应时间从 80ms 爬到 300ms我盯着这个数字盯了半小时完全说不出原因因为服务端对我而言就是个黑盒。后来复盘原生 JMeter 的短板其实很集中。一是负载模型太粗线程组基本只有固定线程数 循环次数 ramp-up这几个旋钮想做阶梯加压、波浪加压、按到达率加压这些更贴近真实流量形态的模型得靠逻辑控制器硬拼拼到最后脚本自己都读不下去。二是服务端不可观测TPS 掉一半你不知道是 CPU 打满、内存开始换页、磁盘 IO 堵住还是连接数撞墙光靠客户端一条响应时间曲线根本归不了因。三是数据处理偏弱参数化、断言、结果清洗这些每天都要碰的活儿原生组件能做但做起来笨尤其是从数据库取值、按随机顺序读 CSV 这种高频需求。这三个短板正好对应三类插件加一类监控体系线程组类插件、结果图表类插件、数据处理类插件以及服务器资源监控。jmeter 插件和服务器监控在我这里从来不是两个独立话题它们必须串成一条链路才有意义——脚本负责把压力发出去监控负责告诉我压力打到哪儿去了。把这条链路想清楚后面挑插件就不会乱。1.2 插件来源分三层优先级别搞反市面上的 JMeter 扩展来源很杂我习惯按三层来分装的时候也从第一层往第三层走。第一层是Plugins Manager 能直接检索到的包也就是 jmeter-plugins.org 维护的那批包名大多带jpgc-前缀。这批的优势是版本有人管、依赖有人管、装上就能在菜单里看到出问题概率最低。我 90% 的场景只在这一层里找。第二层是官方一直在更新、但没进插件管理器索引的组件典型代表就是 JSON / YAML 相关的处理包、MQTT 采样器这类。它们通常要自己下 jar 丢进lib/ext版本冲突得自己盯。第三层是第三方自研或公司内部封装的插件。这一层看着自由实际维护成本最高——原作者不更了、JMeter 升级后二进制不兼容、内部有人改过代码没留说明这种坑我踩过不止一次。所以我的原则是能用第一层解决就绝不碰第三层除非有非它不可的理由。顺带说一句网上搜jmeter 下载时经常会混进一堆和性能测试无关的东西比如各类编辑器插件、下载器扩展、游戏画质补丁之类那些跟本话题不在一个频道上别被搜索结果带偏。JMeter 的扩展只从官方站点和可信仓库走这是底线。1.3 我筛插件时看的三个硬指标装插件不是越多越好装多了启动变慢、菜单变乱、还容易互相打架。我自己的筛选标准有三条分享出来你可以直接套。第一这个插件补的是能力缺口还是只是让我少点几下鼠标。前者装后者不装。比如 Ultimate Thread Group 补的是负载模型能力必装而某些只是把三个组件打包成模板的插件完全可以不加。第二它是否引入额外依赖或额外进程。PerfMon 要在被测机上跑一个 ServerAgent 进程这就属于引入额外依赖必须评估部署成本和端口开通成本不能想当然。第三它的输出能不能被下游消费。插件产生的数据要么能进 JTL 文件要么能在 HTML 报告里体现要么能被外部监控平台接住。如果一个插件只在 GUI 里画个图、导不出来那它能提供的价值就非常有限只适合临时看一眼。这三条不是拍脑袋定的是我被装了十几个插件最后用不上三个坑过之后的结论。你如果刚开始搭环境建议先只装后面第 2 章列的那几个核心包跑顺了再按需加。2. Plugins Manager 与常用插件安装实操2.1 版本对应关系先对齐再动手插件装不上的问题八成出在版本没对齐。JMeter 从 5.x 开始插件管理器是独立 jar 包不再随主程序发布得自己放。同时它对 JDK 版本也有要求JMeter 5.6 以上建议 JDK 8 或 11跑 JDK 17 也能用但个别老插件会报类找不到。落位很简单两个 jar 各就各位# 插件管理器本体放 lib/ext cp jmeter-plugins-manager-1.10.jar /opt/apache-jmeter-5.6.3/lib/ext/ # 命令行运行器插件管理器用它执行一些后台动作放 lib cp cmdrunner-2.2.jar /opt/apache-jmeter-5.6.3/lib/cmdrunner这个包经常被漏掉漏了之后表现是插件管理器能打开、能勾选但点安装没反应或者直接抛异常。我第一次装就栽在这折腾了四十分钟才反应过来少了个 jar。放完重启 JMeter在Options菜单里看到Plugins Manager就说明挂载成功了。注意不同 JMeter 版本对应的插件管理器版本不同5.4 以前用 1.4 左右的版本5.5 以后建议 1.8 以上。jar 包名里的版本号和你主程序的版本对不上先怀疑这里。2.2 核心插件清单每个说清楚解决什么下面这几个是我每次重装环境都会勾上的按用途分组说。负载模型类主要是Custom Thread Groups勾选安装后会带出 Ultimate Thread Group、Stepping Thread Group、Arrivals Thread Group 三个。Ultimate 是最好用的一个它用表格描述每一批线程什么时候起、维持多久、什么时候停做阶梯加压和持续压测直接填表就行不用再拿逻辑控制器拼。Stepping 更适合看系统在逐级加压下的拐点。Arrivals 是按每秒新增多少请求来配适合模拟真实用户的到达节奏而不是简单的并发数。结果图表类3 Basic Graphs和5 Additional Graphs是一对。前者给响应时间、吞吐量、活跃线程三条基础曲线后者给响应时间分布、每秒响应数、事务数、延迟和连接时间等更细的维度。这两个包最大的价值是把结果从一堆数字变成能看出形状的线找拐点特别直观。如果你还要做趋势对比可以再加jpgc-graphs-dist。服务端监控类就是PerfMon Metrics Collector包名jpgc-perfmon。它负责在压测过程中同步采集被测机的 CPU、内存、磁盘、网络。这个包本身只是 JMeter 侧的采样器被采端还要部署一个 Agent第 3 章细说。数据处理类Random CSV Data Set解决CSV 顺序读导致所有线程拿同一批数据的问题jpgc-functions提供一批增强函数比如生成 UUID、随机串、加密摘要这类JSON/YAML Plugins让 JSON 断言和 JMESPath 提取更顺手。调试类Dummy Sampler是我用得最多的一个。它不发真实请求可以自定义响应码、响应体、延迟时间用来验证断言逻辑、后置处理器、正则表达式对不对比拿真实接口试错快得多也不会污染服务端日志。埋一个经验点装完插件后菜单会多出一大块建议顺手把不用的快捷键和面板清理一下尤其团队共用一套脚本时插件差异会导致脚本在别人机器上打不开——JMeter 遇到未知组件会直接报错并忽略该元件这个坑后面第 5 章会讲。2.3 下载慢或者拉不下来怎么办插件管理器的索引和包都在境外站点网络条件不好的时候进度条会一直转。这种情况我有两个应对方式按优先级排。优先方式是在一台能正常访问的机器上装好然后把整个 JMeter 目录重点是lib/ext、lib、bin下的新增文件打包拷过来。插件管理器装完后新增的 jar 基本都落在lib/ext里少数辅助文件在lib一起带上就行。跨机器迁移时记得确认目标机器的 JDK 版本一致否则可能出现类版本不匹配。次选方式是手动下离线包再铺。以 PerfMon 为例从官方仓库下JMeterPlugins-Standard-x.x.x.zip解压后把lib/ext里的 jar 覆盖过去重启即可。这种方式最麻烦的地方是依赖PerfMon 依赖的基础包如果缺失采出来的数据会不全表现是只有 CPU 没有磁盘 IO遇到这种先检查是不是只装了一个 jar。提示不管用哪种方式装完都别急着跑正式脚本用一个最简单的 HTTP 请求验证一下确认插件真的在场。2.4 装完怎么确认插件真的生效确认方式分三层逐层排查最省时间。第一层看菜单重启后Options、Add里能不能找到对应元件找不到就是 jar 没落位或者版本冲突。第二层看启动日志JMeter 启动时bin/jmeter.log会记录加载了哪些扩展包有异常会打堆栈这是排查类找不到问题最快的地方。第三层做一次功能验证比如挂一个 Dummy Sampler 配一个响应断言看断言能不能正常判定能判定说明扩展加载链路是通的。我一般会把这三步写成一段笔记放在团队文档里新人配环境照着走基本不用问我。另外补一句如果脚本要交给别人跑最好在项目说明里列清楚用到的插件和版本号这一步花两分钟能省掉对方半天的排查时间。3. 服务器监控PerfMon 与 Prometheus Grafana 两条路线3.1 ServerAgent 部署端口和权限是两个坎PerfMon 的完整链路是JMeter 侧挂PerfMon Metrics Collector采样器被测机上跑ServerAgent两者通过网络通信JMeter 每 N 秒拉一次指标并写进 JTL。Agent 包在JMeterPlugins-Standard的压缩包里解压后目录里带startAgent.sh和startAgent.batLinux 下先赋执行权限unzip ServerAgent-2.2.3.zip cd ServerAgent-2.2.3 chmod x startAgent.sh ./startAgent.sh --tcp-port 4444 --udp-port 4445默认控制通道走 4444部分版本的数据回传还会用到 4445如果你的压测机跨网段访问被测机这两个端口都要放通而且注意 UDP 也是要放的。这是最常见的第一个坎——JMeter 侧显示Waiting for sample转圈八成就是端口没通。第二个坎是权限。采集磁盘 IO、网络 IO、进程信息这些指标在 Linux 下需要读/proc下的部分文件普通用户有时拿不到完整数据表现是 CPU 和内存有数、磁盘 IO 是空的。解决方式是用有足够权限的用户启动 Agent或者只勾选确实能采到的指标不要勾一堆空指标污染报告。顺带说一个部署细节Agent 是常驻进程压测结束后记得关掉。我见过有同事忘了关第二天做基线对比时发现机器上挂着一堆 Agent 进程虽然不占多少资源但对排查问题时的干扰是实打实的。3.2 JMeter 侧采样器怎么配才不白采PerfMon Metrics Collector的配置有几处容易配错。第一个是主机和端口主机填被测机 IP端口填 Agent 的 4444多个被测机就加多行每一行独立配指标。第二个是指标选择。常用的有 CPU、Memory区分 Physical 和 Swap、Disks I/O读写字节数、读写次数、队列长度、Network I/O、TCP 连接数、Processes。我的建议是只勾和本次压测目标相关的指标比如压的是 IO 密集型服务磁盘队列长度和读写次数必勾压的是纯计算型接口CPU 和内存就够。指标勾多了采样间隔内采集本身会带来额外开销还可能让 JTL 文件膨胀得很快。第三个是采样间隔。默认 1 秒短时间高压测下这个粒度合适如果是持续几小时的长时间压测间隔调到 5 秒甚至 10 秒数据量能降一个量级趋势照样看得清。这一点很多人不注意结果压测跑完 JTL 大得打不开。配好之后跑一次短测,在监听器里看曲线是不是和客户端曲线同步出现。如果服务端曲线是一条平直的线多半是 Agent 没采到值别急着下服务端没压力的结论。3.3 Prometheus Grafana 这条路的优势在哪PerfMon 胜在轻、快、和 JMeter 天然集成缺点是它只在压测期间采压测前后的机器状态看不到。如果你的团队本来就有Prometheus 平台监控服务器资源的基础设施那我更推荐直接用现成的监控栈压测时只要把时间窗对准就行。做法很简单被测机上跑一个node_exporter它把 CPU、内存、磁盘、网络、文件系统、负载等指标暴露成 HTTP 接口nohup ./node_exporter --web.listen-address:9100 /dev/null 21 Prometheus 侧加一条抓取任务指向被测机IP:9100Grafana 侧导入 Node Exporter 全量看板这一步网上资料很多不再展开。做完之后压测期间产生的所有资源曲线都会被持续记录Grafana 的时间轴上你可以任意缩放回看压测开始前 10 分钟、结束后 10 分钟的机器状态这对判断压测期间 TPS 掉是因为上一轮压力还没释放这种问题特别有用。进阶一点的做法是把 JMeter 自己的指标也推进监控体系。社区有把 JMeter 结果推到 Pushgateway 的方案这样客户端和服务端的曲线能画在一张图上找拐点的效率会高很多。代价是要多维护一套推送逻辑脚本改动量不小值不值得看你团队的压测频次。3.4 时间对齐是最容易被忽略的坑这一条我想单独拎出来讲因为它几乎每次压测都会有人踩。JMeter 机器和被测机如果时钟不同步两边曲线在图上错开几十秒甚至几分钟你拿服务端 10:05 的 CPU 峰值去解释客户端 10:02 的响应时间抖动结论就是错的。解决办法很朴素压测前用 NTP 把 JMeter 机器、被测机、监控服务器的时间都校准一次误差控制在 1 秒以内。压测结束后先对一下三台机器的时间戳偏差再开始分析。第二个对齐点是 Grafana 的时间窗。默认时区如果和服务器时区不一致曲线整体会平移。我第一次用 Grafana 做压测分析时明明压测是下午两点开始图上的压力段显示在早上六点找了半天才反应过来是时区问题。分析前先把 Grafana 的时区设成和你日志一致的时区这一步花十秒钟能省掉一次误判。注意跨时区团队协作时所有时间统一用 UTC 记录展示层再转本地时区。日志和监控两边时区规则不一致是最折磨人的问题。4. 压测脚本里的高频场景录制、参数化、断言、文件上传4.1 HTTPS 脚本录制与证书导入录制是搭脚本最快的方式尤其是业务链路长、参数多的场景。JMeter 从 3.x 起就内置了HTTP(S) Test Script Recorder位置在测试计划下添加非测试元件。HTTPS 录制的前提是证书。第一次启动录制器时JMeter 会在bin目录生成一个ApacheJMeterTemporaryRootCA.crt临时证书你需要把这个证书导入到发起请求的客户端浏览器或系统的受信任根证书列表里否则抓到的请求会直接失败。这一步在 Windows 上是双击证书导入选受信任的根证书颁发机构在 Linux 上是往系统证书库里复制并更新信任链。导入完成后把客户端的网络出口指向127.0.0.1:8888这个 8888 就是录制器的监听端口。然后在录制器界面上点启动客户端上正常操作一遍业务流程请求就会被记录下来。录完记得把网络出口改回去不然客户端会一直走录制器关了 JMeter 之后直接上不了网。录出来的脚本不能直接用一定要做三件事一是清理无关的静态资源请求用URL Patterns to Exclude把图片、CSS、JS 过滤掉不然脚本里一半是垃圾请求二是排查是否有敏感信息被明文写进请求参数密码、令牌这类字段要换成变量或配置元件管理三是核对每个请求之间的依赖关系尤其是带会话、带前置单号的链路录制器不会帮你处理关联得自己加正则提取器把上一步的返回值传给下一步。4.2 数据库参数化取值怎么写用数据库里的真实数据做参数化是让压测更接近真实场景的关键一步。整套配置由三个元件组成JDBC Connection Configuration负责建连接池JDBC Request负责执行查询并把结果存进变量CSV Data Set Config或者循环控制器负责把变量按行分配出去。先配连接池。填数据库地址、库名、账号密码以及 JDBC 驱动类名比如 MySQL 用com.mysql.cj.jdbc.Driver。驱动 jar 要放到lib目录下不然启动就报找不到类。这里有个小坑JDBC 密码在 JMX 文件里是明文存储的脚本传出去等于把库密码传出去了团队协作时要么脱敏要么把密码放到外部属性文件里用${__P()}读。再配查询。在JDBC Request的 Query 里写 SQLVariable Names填一个名字比如user_ids。JMeter 会把结果按user_ids_1、user_ids_2这样编号存变量同时提供user_ids_#表示结果行数。取值的时候要自己算行数和随机索引这是最容易出错的地方很多人以为变量名写上去就能自动循环其实不会。我的做法是加一个 JSR223 前置处理器用${user_ids_#}拿到总行数随机生成一个索引再拼出变量名去取值。这样每个线程每次都能拿到不同数据避免所有线程都拿第一行的情况。用 CSV 文件做参数化时同理顺序读会让所有线程开头都拿到同一批数据Random CSV Data Set插件就是专门解决这个问题的。提示查询结果集别太大几十万行全读进内存会直接把 JMeter 的堆撑爆。用LIMIT限制一下采样样本够用就行。4.3 BeanShell 断言和 JSON 断言怎么选断言决定压测结果可信度我一直觉得这是整个脚本里最不能被忽略的部分。原生 JMeter 提供了响应断言、大小断言、持续时间断言配合BeanShell Assertion可以做复杂逻辑判断比如解析响应体、校验业务码、比对字段值。BeanShell 断言的基本写法是在脚本里判断条件不满足就设置失败标志String resp new String(ResponseData); if (!resp.contains(\code\:\0000\)) { Failure true; FailureMessage 业务码非成功: resp; }但我要说一个实际经验BeanShell 解释执行性能很差在高并发下它会成为瓶颈尤其是每个请求都跑一段脚本时。我的替代方案是优先用JSON Assertion和JMESPath Assertion这类专项断言它们底层是编译执行效率高得多。只有在逻辑确实复杂、需要写多行分支判断时才用 JSR223 Groovy它同样支持Failure和FailureMessage变量速度比 BeanShell 快一个数量级。还有一个常见错误是断言写在错误的层级。断言加在采样器下只对那一个请求生效加在线程组下会对组内所有采样器生效加在测试计划下会全局生效。放在错的层级表现为有的请求明明失败却没被标记或者一个正常的静态请求把整个事务判失败。4.4 RESTful 参数与文件上传的写法现在接口大多是 RESTful 风格JMeter 的 HTTP 请求元件直接支持 GET、POST、PUT、DELETE、PATCH。写这类脚本有几个固定套路。路径参数直接拼在 URL 里比如/api/orders/10086。查询参数用Parameters面板加注意勾上编码。请求体参数切到Body Data面板写 JSON同时必须加一个HTTP Header Manager把Content-Type设成application/json否则服务端很可能按表单解析直接返回 400 或参数为空。这个错误我见过太多次表现是 Postman 里好好的到 JMeter 就是取不到参数。文件上传要勾选Use multipart/form-data然后在Files Upload里填文件路径、参数名、MIME 类型。三点提醒路径尽量用相对路径配合CSV Data Set Config管理方便换机器被测服务通常对上传大小有限制超过会直接断连这种报错在客户端表现为error writing to server测试用的文件不要放太大几百 KB 到几 MB 就够除非你专门要测大文件传输。令牌、会话这类鉴权信息统一放到HTTP Header Manager里值用变量引用变量值放在User Defined Variables或者从上一个接口的响应里提取。这样脚本结构会清爽很多换环境时只改变量不用满脚本找硬编码。5. 常见报错与排查速查5.1 error writing to server 到底在说什么java.io.IOException: error writing to server是 JMeter 里出现频率最高的报错之一它的字面意思是往服务端写请求数据时出错也就是请求还没发完这个连接就废了。原因基本集中在四类。第一类是请求体太大尤其是上传文件场景服务端设了请求体积上限超过就直接掐断连接。第二类是服务端处理超时主动断连客户端还在写就被 reset 了。第三类是长连接复用的问题JMeter 默认开启 keep-alive某些服务端或中间层在空闲一段时间后关闭连接JMeter 复用这个已关闭的连接就会报这个错解决办法是在 HTTP 请求的Advanced里取消勾选Use KeepAlive或者给 HTTP 采样器加一个Connection: close的请求头。第四类是客户端资源不足堆内存给小了大响应体处理不过来这个通常伴随 Full GC 日志。排查顺序我的习惯是先看压测并发量和报错比例的关系只在高压下出现多半是连接复用或资源问题固定比例出现多半是数据问题单个采样器稳定报错就单独复现把日志级别调成 debug 看完整堆栈。这份经验值钱的地方在于光看这行报错本身是推不出原因的得结合并发规模和复现规律一起判断。5.2 插件装了却不生效的四种可能这个问题我在不同团队里至少被问过十次原因基本跑不出下面四种。一是 jar 放错目录。JMeter 的扩展类要放在lib/ext放在lib下只会被当普通依赖加载元件不会出现在菜单里。二是缺依赖包比如插件管理器少了 cmdrunnerPerfMon 少了基础包。三是同名的老版本 jar 还留在目录里两个版本同时存在某一个被优先加载导致功能异常这种情况把旧版本删掉就行。四是脚本打开时报未知元件那是因为你本机没装对方用到的插件JMeter 会忽略这个元件继续跑但它对应的逻辑就丢了——这也是为什么我坚持在项目文档里写清楚插件清单。排查最快的方式是看bin/jmeter.log启动时每个扩展包的加载情况都有记录异常也会打堆栈。别看界面看日志这是省时间的关键。5.3 结果树导出和内存的那点事GUI 下的察看结果树是调试利器但它是内存杀手。默认它会把所有请求的完整响应体缓存在内存里几千个请求就能把堆吃满特别是响应体很大的接口。表现是界面越来越卡最后 OOM。正确做法是调试阶段才开结果树而且只保留错误请求把Log/Display Only设成Errors跑正式压测时把结果树关掉。要留存数据就用Simple Data Writer或者非 GUI 模式下的-l参数直接写 JTL 文件格式选 CSV别选 XML——XML 格式的 JTL 体积能大出好几倍解析也慢。导出结果也有讲究。压测结束后用命令行把 JTL 转成 HTML 报告jmeter -g result.jtl -o ./report生成的报告里有聚合表、响应时间曲线、吞吐量曲线、错误分布比 GUI 上截图规范得多直接能给到评审会。5.4 一百个并发的报告怎么读才不误导人模拟 100 用户并发跑完报告里字段一大堆我通常按下面的顺序看你也可以照着来。先看Error %这是门槛指标超过 1% 就别往下面看了先解决报错。然后看90% Line和95% Line这两个比平均值有参考价值得多平均值会被极端样本拉偏90 线更能反映大部分用户的真实体验。接着看Throughput注意它和并发数的关系并发涨了吞吐不涨说明系统已经到瓶颈并发涨了吞吐反降说明资源在争抢这时候一定要对照服务端监控曲线看是哪块资源先满。最后看Received KB/sec估算一下带宽有没有成为瓶颈。还有一个必须提醒的点并发用户数不等于每秒请求数。100 个线程如果在跑一个响应时间 500ms 的接口实际 TPS 大概在 200 上下线程数除以响应时间才是粗略的请求速率。用线程数当 TPS 去写报告是最常见的误读评审会上被人问一句就露馅了。我自己做性能测试这几年越来越觉得工具本身不是门槛门槛在于能不能把客户端数据和服务端数据对起来讲一个完整的故事。脚本写得再花哨报告里只有一条曲线那这个测试的价值就只剩一半。反过来哪怕是几十行 Thread Group 加一个 PerfMon 曲线只要你能指着 CPU 曲线和响应时间曲线的交点说清拐点在这儿、原因是什么这个结论就站得住。插件和监控工具都是为这句话服务的别本末倒置。
返回列表