ARTICLE DETAIL

资讯详情

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

JMeter压测必配的系统资源监控:CPU、内存、磁盘与网络瓶颈定位实战

JMeter压测必配的系统资源监控:CPU、内存、磁盘与网络瓶颈定位实战 做性能压测这些年有一个场景我印象特别深一个接口压到 500 并发响应时间曲线平得跟湖面一样TPS 也稳在预期范围大家正准备收工写报告。结果运维那边突然喊起来说应用服务器 CPU 已经 99% 跑了快十分钟磁盘 I/O 排队长度也异常得离谱。这时候才意识到一个扎心的事实——我们用 JMeter 压了一下午看到的只是服务还活着的表象对服务器内部到底经历了什么几乎一无所知。从那次之后我养成了一个习惯任何一次 JMeter 压测都要把系统资源监控当成标配去做而不是可选项。CPU、内存、磁盘、网络这四项指标配合 TPS、响应时间、错误率一起看才叫完整的压力测试。这篇文章就把我常用的方案、配置和踩坑经验完整写出来新手可以直接照着搭老手也能看看有哪些容易忽略的细节。1. 压测只盯响应时间等于没测监控指标与瓶颈定位的关系很多人对压测的理解是用 JMeter 不停地打请求看接口响应快不快。这句话对了一半另一半恰恰是测试的核心价值所在——通过资源指标判断系统的容量上限和瓶颈位置。1.1 响应时间正常但系统快崩溃为什么会出现这种假象出现文章开头那种情况根本原因在于接口的响应时间只是应用层的结果而系统资源是底层的原因。一个接口返回 200ms可能是在 CPU 已经打满的情况下靠着负载均衡轮询、线程排队硬撑出来的也可能是内存即将溢出GC 频繁压缩堆空间换来的片刻平静。举一个最常见的例子Tomcat 默认线程池 200当请求进来后前 200 个请求正常处理第 201 个请求开始排队等待。此时从 JMeter 看响应时间会随着队列长度缓慢增长TPS 可能不再上升甚至下降。但如果你只看响应时间是否超标往往会得出系统还有余量的错误结论。而一旦你加上 CPU 监控就会发现处理请求的那几个线程早就把 CPU 跑满了排队不是网络问题是 CPU 处理不过来了。所以压测必须回答三个问题系统能支撑的最大并发放量是多少达到这个并发时CPU、内存、磁盘、网络分别处于什么状态第一个到达瓶颈的资源是谁这个资源决定了系统的真实上限。1.2 压测中必须同时观察的六个维度从我的实践来看一份合格的压测监控数据至少包含下面这些维度关键指标说明应用层TPS/QPS每秒事务数衡量系统处理能力应用层响应时间平均/90%/99%用户体验直接相关应用层错误率超过 0.1% 就需要重点排查系统资源CPU 使用率用户态内核态等待 I/O 的比例系统资源内存使用率物理内存、Swap、GC 情况系统资源磁盘 I/O利用率、读写速率、队列长度系统资源网络带宽吞吐量、连接数、丢包率我自己习惯把应用层指标和资源指标放在同一张图里看时间轴对齐这样做的好处是当 TPS 掉下来的时候一眼就能看出是哪个资源先到达瓶颈的。如果 CPU 先到 100%说明是计算密集型瓶颈如果内存持续增长然后 GC 频繁说明可能是内存泄漏或堆配置不合理如果磁盘繁忙度先到 100%那多半是日志写入或者数据库落盘拖了后腿。2. 从零搭建 JMeter 压测环境安装配置与第一个压测脚本既然要聊完整的压测方案先花点篇幅把 JMeter 本身的环境捋清楚。虽然很多搞开发的同学电脑里已经装了但实际用起来还是有不少细节容易被忽略。2.1 Windows 和 Linux 下的安装要点JMeter 是基于 Java 的工具所以第一步永远是装 JDK。这里有个版本搭配的问题JMeter 5.x 系列要求 Java 8建议直接上 Java 11兼容性最稳。JMeter 5.5 之后开始完整支持 Java 17。如果你用的版本比较新直接配 Java 17 就行性能上还有小幅提升。安装过程本身就三步下二进制包、解压、配置环境变量JMETER_HOME。Windows 下我建议直接解压到D:\apache-jmeter-x.x.x这种不带空格的路径别放在C:\Program Files下面不然某些脚本和插件跑起来容易遇到路径解析问题。启动方式要记住两种带界面模式jmeter.batWindows或jmeter.shLinux/macOS用于编写脚本和调试会消耗额外的 GUI 内存。命令行模式jmeter -n -t test.jmx -l results.jtl -e -o report_dir正式压测必须用这个。注意正式压测时压测机本身也会消耗 CPU 和内存如果压测负载很大比如线程数非常多、采样频率很高压测机和被测服务器最好分开两台机器避免互相干扰互相拖垮。2.2 一个最小可用的 HTTP 接口压测脚本配置创建一个基本的压测脚本核心是配置线程组和HTTP 请求。我在实际项目中一般这样设置线程组参数线程数Number of Threads模拟并发用户数这个值不是越大越好取决于测试目标。比如要测某个接口的容量上限可以从 50 开始逐步递增。Ramp-Up Period秒达到最大并发需要的时间。如果设 10 秒、100 个线程相当于每秒启动 10 个新线程。循环次数建议勾选无限然后配合调度器设置持续时间比如 5 分钟、15 分钟这样比固定循环次数更能模拟真实流量的持续压力。HTTP 请求配置协议http 或 https服务器名称或 IP被测服务地址端口号如 8080方法GET/POST 按接口文档来路径接口路径如果是 POSTBody Data 里填 JSON同时加一个 HTTP 头管理器设置Content-Type: application/json这里有个常用的小技巧把线程数和持续时间做成 JMeter 属性变量比如${__P(threads,100)}和${__P(duration,600)}这样命令行压测时可以灵活传入参数不用每次改脚本jmeter -n -t pressure_test.jmx -Jthreads200 -Jduration900 -l result.jtl -e -o report命令行跑完以后report目录下会生成一份 HTML 报告里面有 TPS、响应时间分布、错误率这些基础数据。但注意这份报告只有 JMeter 自身视角的数据真正的血泪教训是——它不会告诉你服务器 CPU 是不是已经烧开了磁盘是不是在狂写日志。3. 四类系统资源指标的采集方案PerfMon、ServerAgent 与命令行备选要采集被测服务器的 CPU、内存、磁盘、网络指标业界用得最普遍的一套组合是JMeter 插件管理器安装PerfMon (Servers Performance Monitoring)插件在被测服务器上部署ServerAgent这套方案的好处是JMeter 的监听器里可以直接看到资源指标的实时曲线和 TPS、响应时间放在同一个界面里对比压测完还能把数据导出成 CSV 再做分析。3.1 用 PerfMon ServerAgent 采集指标的完整步骤第一步安装 PerfMon 插件。在 JMeter 里打开 Plugins Manager没装的先去官网下载 plugins-manager.jar 放到 lib/ext 目录在 Available Plugins 标签里搜 PerfMon勾选后点击 Apply重启 JMeter 生效。第二步部署 ServerAgent。从 ServerAgent 官网下载对应平台的压缩包传到被测服务器解压。Windows 直接双击startAgent.batLinux 下执行chmod x startAgent.sh ./startAgent.sh默认监听端口是 4444注意防火墙一定要放行这个端口否则 JMeter 侧会一直报错Cant connect to host。我遇到过一个很有意思的情况服务器有自己的防火墙策略但云安全组也有一层过滤两边都得配好才行。第三步添加 PerfMon Metrics Collector 监听器配置要监控的指标。在测试计划里添加监听器 - PerfMon Metrics Collector然后在界面里添加监控项CPU选择CPU指标监控 Overall CPU 使用率内存选择Memory关注 Used Memory磁盘选择Disks I/O可以监控读写速率或者选Disks (percent busy)看繁忙程度网络选择Network I/O看实际吞吐量单位是 KB/s这里我一般会写一个 JSON 格式的配置模板方便复用{ hosts: [ { host: 192.168.1.100, port: 4444, metrics: [ { type: CPU, result: Overall CPU Usage }, { type: Memory, result: Used Memory }, { type: Disks I/O, result: Percent Busy }, { type: Network I/O, result: Bytes Received/Transmitted } ] } ] }3.2 没有插件时的备选方案操作系统自带工具PerfMon 不是任何时候都好使比如有些生产环境出于安全考虑不允许额外部署 Agent这时候就要退回操作系统自带的工具来采集。Linux组合使用top看 CPU/内存iostat -x 1看磁盘 I/O 详情vmstat 1看系统整体状态sar -n DEV 1看网络吞吐。这些命令本身是文本输出压测过程中可以重定向到文件保存。top -b -d 2 cpu_mem.log iostat -x 2 disk_io.log vmstat 2 vmstat.log sar -n DEV 2 network.logWindows用系统自带的性能监视器perfmon.msc添加计数器「Processor Time」「Available MBytes」「Physical Disk Bytes/sec」「Network Interface Bytes Total/sec」即可输出到数据收集器集压测结束直接导出 CSV。备选方案虽然没有 PerfMon 那么直观但在大多数情况下已经够用。我自己在性能测试时通常会同时启动 ServerAgent 和 vmstat 记录两边数据互相印证防止 Agent 自身出问题导致数据缺失。4. 压测数据怎么解读曲线联动的四个典型瓶颈场景监控数据采集了图也画了但很多新手会卡在最后一步——不知道怎么看图。这一节用四个我真实遇到过的瓶颈场景把曲线联动的分析方法讲透。4.1 CPU 打满但 TPS 不再增长计算型瓶颈现象并发量从 100 升到 200TPS 先是跟着涨到某个临界点后原地踏步响应时间开始缓慢上升。同时 PerfMon 里 CPU 已经稳定在 90% 以上。判断系统是 CPU 密集型瓶颈。此时再继续加压已经没意义TPS 的上限是 CPU 决定的不是在应用层调个参数能解决的。常规处理思路检查是否有死循环、锁等待、频繁的上下文切换。分析应用线程栈看看 CPU 时间消耗在哪个方法上。可以用top -Hp pid找到最耗 CPU 的线程 ID再换算成十六进制用jstack去匹配线程栈。如果确认是业务代码计算逻辑太重优化算法或者加缓存如果是资源争抢考虑扩容增加 CPU 核数或者横向加节点。4.2 内存持续上涨后 TPS 出现周期性锯齿GC 问题或内存泄漏现象Memory 曲线随时间不断抬升TPS 曲线呈现出上升-突降-再上升的锯齿状。在 JMeter 聚合报告里能看到 GC 停顿导致的响应时间尖刺。判断Java 应用内存分配跟不上垃圾回收频繁触发 Full GC每次 Full GC 都会 Stop-The-World表现为周期性卡顿。排查路径用jstat -gcutil pid 1000观察 GC 情况重点看 FGCFull GC 次数和 FGCTFull GC 耗时。如果 Full GC 后内存能降下来说明是堆配置偏小在启动参数里调整-Xms和-Xmx一般建议两个值相等避免堆动态伸缩带来的性能损耗。如果 Full GC 后内存降不下来甚至越涨越高十有八九是内存泄漏。配合jmap -dump:formatb,fileheap.hprof pid导出堆快照用 MAT 或 VisualVM 分析哪个对象占着内存不释放。补充一点如果压测的并发数一直不变但内存占用一路爬升没有下降的迹象这就是泄漏的早期信号不用等我上面提到的 GC 次数直接截图丢给开发就完了。4.3 磁盘 I/O 先于 CPU 到达瓶颈日志和落盘拖垮接口现象CPU 才 40%内存也正常但 TPS 很低接口响应不稳定。PerfMon 里 Disks 显示 Percent Busy 经常冲到 100%读写速率很高。判断瓶颈在磁盘。最常见的原因是日志框架同步写盘、数据库每次请求都提交、或者中间件在高峰期大量刷日志。实际处理办法先把日志级别从 DEBUG 调到 INFO 或 WARN压测场景下这是最立竿见影的优化。查看磁盘读写分布用iostat -x 1看%util和await。如果await大而svctm小说明 I/O 队列太长磁盘已经忙不过来了。如果是数据库落盘问题考虑批量提交、异步刷盘、或者把数据和日志放到不同磁盘上。硬件层面看是否 SSD如果是机械盘在高并发随机写场景下很容易成为瓶颈。4.4 网络带宽打满而服务器资源正常压测机带宽先撑不住现象被测服务器 CPU、内存、磁盘都正常但 JMeter 侧响应时间越来越长TPS 上不去。PerfMon 的 Network I/O 显示带宽跑到接近网卡上限。判断瓶颈在网络链路既可能是带宽跑满也可能是连接数达到上限比如 TCP 连接耗尽。这一点在压测中非常容易被忽略特别是局域网内压测时如果被测服务返回的数据包很大比如某个接口返回几百 KB 的 JSON压测机网卡带宽可能先被打满导致请求发不出去响应也接收不回来。这种时候不是服务端能力不行而是压测链路本身到达了极限。一个务实的做法查看 JMeter 所在机器的网卡流量如果已经接近千兆约 118 MB/s上限需要用分布式压测或改用更小数据量的接口来做压力测试。5. 压测过程中的常见坑与排查记录从一次真实压测说起最后分享一次真实压测的完整排查过程把前面涉及到的内容串起来。也能帮大家避开一些我在实战中踩过、见别人踩过的坑。5.1 场景复现CPU 报错引发的中断和监控 Agent 的假数据那一次是给一个内部管理系统做上线前压测。JMeter 脚本配置的是 300 并发、持续 30 分钟。压测刚开始 5 分钟PerfMon 曲线显示 CPU 达到 100%但 TPS 还在缓慢上升响应时间也没明显恶化。我当时有点疑惑于是立刻到服务器上用top复核。top显示 CPU 确实是 100%但用户态us只占 30%内核态出现了一个异常现象——大量 CPU 时间花在了软中断和硬中断上进程列表里ksoftirqd占了不少 CPU。顺着这个线索查下去发现这台服务器上跑着一个定时采集监控数据的 Agent它每秒钟会向外部上报一次全量系统状态而外网网关恰好有问题导致 Agent 一直在重试引发了频繁的网络中断。说白了这个 CPU 压力有一部分是监控系统自己造成的。这个例子说明两件事系统性能数据要交叉验证。PerfMon 或 ServerAgent 采集到的数据配合服务器本地命令复核能区分是业务压力导致的瓶颈还是监控/运维组件自身造成的假象。压测前要充分确认被测环境干净。隔离的测试环境最好如果必须在共享环境压测先记录一下压测前的资源基线压测后的增量才是有效数据。5.2 容易踩的五个坑与对应的规避方法ServerAgent 端口连不上。不只是服务器防火墙云安全组、Linux 的 SELinux 都可能拦住 4444 端口。排查顺序先 telnet 端口通不通再查防火墙再查安全组。压测机资源不够。单台 JMeter 在超过 1000 并发时采样数据的写入和聚合本身就占大量 CPU/内存。这时候要上分布式压测主节点控制多个从节点各自产生压力。记得每台从节点运行jmeter-server主节点脚本里远程 IP 填从节点地址。监听器过多导致 JMeter 卡死。压测过程中不建议开太多图形化监听器尤其是 View Results Tree 这类会保存每个请求的完整响应体几百并发下内存直接爆炸。命令行模式 简单的聚合报告就够结果用后面的 HTML 报告看。监控数据没有落盘保存。PerfMon 的曲线看完了就不管了后来写报告需要图却没有数据了。建议在 PerfMon 监听器里勾选 Write results to file把监控指标一起存到 CSV后续统一整理。持续压测时间太短。有些团队压 1 分钟就下结论这是大忌。内存泄漏和 GC 问题往往要跑 15 分钟以上才暴露。我的经验是最低 15 分钟有条件的跑 1 到 2 小时让问题充分暴露。5.3 压测完成后的监控数据归档习惯压测结束不是把报告发给开发就完事了。我会把以下几类文件统一归档到每次压测的目录里养成习惯test_20250115/ ├── jmeter_script.jmx ├── results.jtl ├── html_report/ # JMeter 生成的 HTML 报告 ├── server_metrics.csv # PerfMon 采集的资源指标 ├── vmstat.log # 服务器本地记录 ├── iostat.log ├── jstack_thread_dump.txt # 压测峰值时刻抓的线程栈 └── heap_dump.hprof # 如果有内存异常保留堆快照这样做的价值在于当开发改了代码重新压测时可以把两次的 CSV 和 JMeter 报告放在同一张图里对比能非常直观地看出优化有没有生效。比如改之前 CPU 峰值 95%改之后 70%TPS 还提升了一截这种量化的对比比任何口头的性能有提升都有说服力。在做性能监控这条路上我个人的体会是工具本身都不复杂PerfMon 装好、ServerAgent 跑起来、再配合命令行半小时就能搭完。真正拉开差距的是对数据的理解——同样一张 CPU 曲线有人只能看出满了有人能继续挖出是用户态还是内核态是中断还是进程切换再顺藤摸瓜找到具体的代码位置。最后再说一个压测中容易忽视的环节务必在生产环境之外的预发环境做一次完整的压测演练不只是测出系统的性能上限也是验证监控链路本身好不好使、告警阈值设得对不对、日志采样足不足。毕竟压测的目的从来不是为了跑出几个漂亮的数字而是在线上真正出问题之前提前把所有可能拖垮系统的隐患暴露出来。
返回列表