ARTICLE DETAIL

资讯详情

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

JMeter监听器图表分析:从聚合报告到趋势曲线,定位性能瓶颈

JMeter监听器图表分析:从聚合报告到趋势曲线,定位性能瓶颈 先说一个我自己的经历。之前帮一个团队做接口压测脚本跑完聚合报告上明明白白写着平均响应时间 120ms错误率 0%吞吐量 800/s。我当时差点在报告上盖个通过的章但习惯性多看了一眼响应时间曲线发现测试进行到第 3 分钟之后99% Line 直接从 200ms 飙到了 2.8sTPS 也从 800 掉到了 400 以下。后来一查是缓存过期后所有请求同时穿透到数据库连接池被打满。如果只看聚合报告这个瓶颈就会完美地藏起来。这篇文章就是聊这件事的JMeter 监听器里那些常用图表到底每张图在看什么、怎么从图里读出问题、怎么把几张图串成一条证据链去定位性能瓶颈。适合正在做性能测试但总感觉测完了不知道结论是什么的同学也适合需要自己排查线上接口变慢的开发。我会把常用监听器分成三类来讲再给出一个从图表异常到根因确认的完整路径。1. 监听器到底在监听什么先建立瓶颈分析的整体视角JMeter 的监听器Listener不是只有一个而是一整个家族。很多人打开 JMeter 之后习惯性只加一个聚合报告或者察看结果树跑完看一眼就收工这其实是把性能测试做成了功能测试。要定位瓶颈你得知道监听器分几类、每类适合回答什么问题。1.1 监听器的三个类别结果统计、请求明细、趋势曲线按作用来分JMeter 监听器大致可以分成三类。第一类是结果统计类最典型的是聚合报告Aggregate Report、汇总报告Summary Report和用 Simple Data Writer 写出来的 JTL/CSV 结果文件。它们回答的问题是这一轮压测整体表现怎么样平均响应时间多少、错误率多少、吞吐量多少。这类监听器的特点是只看最终汇总数字所以会丢掉时间维度上的细节。第二类是请求明细类最典型的是察看结果树View Results Tree和断言结果Assertion Results。它们回答的问题是具体某个请求长什么样请求头发了什么、响应体返回了什么、断言有没有通过。这类监听器适合在调试脚本和定位具体错误时用正式压测时如果开着它跑全程压测机 IO 会被大量响应体写盘拖垮。第三类是趋势曲线类主要指通过 JMeter Plugins Manager 安装的 jpgc 系列插件比如 Response Times Over Time、Transactions per Second、Active Threads Over Time。它们回答的问题是随着时间推移指标是怎么变化的。瓶颈定位最依赖的就是这一类因为性能问题几乎都是在某个时间点、某个并发量下突然出现的汇总数字会把这种突变平均掉。1.2 为什么单靠一张图很难定位瓶颈定位性能瓶颈本质上是一个从现象逆推原因的过程单张图表给的信息量永远不够。还是拿看病打比方体温计能告诉你发烧了但不知道是细菌感染还是病毒感染更不知道感染灶在哪。聚合报告就是那支体温计它的价值是告诉你系统确实有问题但问题出在哪一层、什么时候开始的、以什么形态出现的需要靠其他图表来补。所以我建议的分析习惯是聚合报告用来确认有没有问题结果树用来确认错误长什么样趋势曲线用来确认问题从什么时候开始、以什么形态扩散最后再结合服务端监控确认问题发生在哪一层。这四条信息凑齐了才能形成一条完整的证据链。后面几节我按这个思路展开。2. 聚合报告与汇总报告别急着看平均值聚合报告大概是 JMeter 里被看最多的监听器也是最容易被误读的。它的字段很多Samples、Average、Min、Max、Std.Dev、Error%、Throughput、Received KB/sec、Sent KB/sec还有 90% Line、95% Line、99% Line。大多数人的习惯是扫一眼 Average 和 Error%然后就开始写报告。但我建议你改一下顺序。2.1 平均响应时间是最会骗人的指标平均响应时间这个指标有两个天然缺陷。第一它对长尾极不敏感。举个例子100 个请求里 99 个耗时 1 秒只有 1 个耗时 100 秒算下来平均响应时间是 1.99 秒看起来还挺健康。但对那 1% 的请求来说100 秒已经完全不可用了。在真实业务里这 1% 也许就是某个关键链路的大查询要么超时重试要么直接把线程池拖垮。第二平均值的波动完全掩盖了变化趋势。同样是平均值 500ms可能是整场压测都稳定在 500ms也可能是前 5 分钟 100ms、后 5 分钟 900ms。这两种情况对应的结论天差地别前者是系统容量正常后者是明显的劣化趋势必须查原因。这就是为什么我每次看聚合报告第一眼看的不是 Average而是99% Line 和 Std.Dev。99% Line 的含义是99% 的请求都在这个耗时以内它比平均值更接近真实用户体验。如果 99% Line 是 Average 的好几倍说明系统里存在明显的长尾请求。Std.Dev 是标准差它衡量的是响应时间的离散程度。Std.Dev 越大说明响应时间的抖动越严重哪怕平均值很低也意味着系统存在不稳定的资源竞争。2.2 Error% 和 Throughput 比平均响应时间更值得关注Error% 这个字段很多人只看是不是 0%。但压测过程中错误率几乎不可能是绝对的 0你需要关注的是两个点错误率有多高以及错误集中在哪个时间段。我见过最典型的场景是整场压测错误率维持在 0.5% 以下看起来很安全但把错误请求按时间戳切开后发现所有错误都集中在压测最后两分钟恰好是数据库连接池被耗尽的时间段。这种集中在尾部的错误远比均匀分布的偶发错误更危险。Throughput 在聚合报告里的单位是每秒完成的事务数也就是大家常说的 TPS。看 TPS 的时候要结合线程数并发用户数一起看。理论上并发数翻倍TPS 应该也翻倍至少不能明显下降。如果并发数上去了TPS 却不涨了说明系统到了处理上限这就是瓶颈出现的信号。另外还要注意聚合报告里的 Received KB/sec 和 Sent KB/sec如果这两个数值接近网卡上限说明瓶颈很可能在带宽而不是应用本身。2.3 压测机自身成为瓶颈时的典型表现这里必须多提醒一句聚合报告里的吞吐量不达标不一定就是服务端的问题压测机自身也可能成为瓶颈。最常见的有三种情况压测机的 CPU 被打满尤其是用 HTTP Client 实现做高并发时、压测机内存不足导致 JVM 频繁 GC、压测机与目标服务器之间的带宽被打满。如果出现这些问题聚合报告上会表现为TPS 到某个值后怎么加压都上不去同时压测机本身的 CPU 或网络指标已经是红的。判断方法很简单压测的时候开个系统监控看一眼压测机的 CPU、内存和网络。如果压测机已经快不行了优先优化脚本和压测方案而不是急着去服务端找问题。这一点在后面的实战路径里还会再提。3. 察看结果树与断言结果从单次请求里挖根因聚合报告告诉你系统有问题下一步就要回答这个错误到底长什么样。察看结果树和断言结果就是干这个的。很多新手把察看结果树当成默认监听器一直挂着跑到一半发现压测机卡得要死这就是采样器消耗资源太多导致的。正确用法是调试阶段开着它正式压测阶段关掉它或者只在出错时记录。3.1 压测阶段不要全量保存采样结果察看结果树默认会把每个请求的请求体和响应体都加载到内存里并显示在界面上。当并发数上来之后光是渲染这些内容就够让 JMeter 界面卡死了。所以我的建议是调试脚本阶段开着察看结果树逐个请求确认参数、断言、关联都没问题。正式压测阶段不加察看结果树改用 Simple Data Writer 把结果写到 JTL 或 CSV 文件中。如果一定要保留响应体就把响应数据字段的长度限制调小或者在结果树里勾选仅记录错误。压测结束后如果需要复盘具体请求再用 JMeter 打开 JTL 文件或者用脚本对 CSV 做过滤分析。这样做不仅是为了保护压测机也是为了保护数据的可分析性。你要知道全量保存 10 万条响应体产生的文件可能是好几个 GB分析的时候反而麻烦。3.2 常见响应体特征与瓶颈类型的对照通过察看结果树看具体请求的响应体通常能直接锁定问题类型。我把平时最常碰到的几类特征整理成了一张表响应体/异常特征可能的瓶颈原因下一步排查方向Connection pool is empty数据库连接池被耗尽检查连接池最大连接数、SQL 执行时长、慢查询Cannot get connection, pool exhausted连接获取等待超时看连接池等待超时配置、线程数是否远超连接池上限Read timed out服务端处理时间过长或下游依赖慢查应用日志、调用链、数据库慢 SQLConnect timed out网络不通、防火墙、负载均衡瓶颈检查网络链路、四层/七层负载均衡连接数429 Too Many Requests触发了限流查限流阈值配置、是否需要对压测流量加白名单503 Service Unavailable应用线程池满了过载保护触发查应用线程池大小、队列长度、GC 情况RejectedExecutionException线程池拒绝新任务看线程池队列是否已满任务积压情况Broken pipe/Connection reset服务端主动关闭了连接查 keep-alive 配置、空闲连接超时策略这张表不是让你背下来的而是给你一个看到特征就能想到去哪查的直觉。大部分性能瓶颈响应体里的异常信息都会直接或间接指向某一层资源。3.3 断言结果不是只用来判断对错的JMeter 的响应断言Response Assertion很多人只用来判断这个请求是不是返回 200这当然没问题但它的价值可以更大。你可以在脚本里加一个简单的断言断言响应体中不包含某个错误关键字或者断言响应时间小于某个阈值。这样在聚合报告里响应时间超标的请求会被标记为失败错误率就直接变成了不达标率。配合断言结果监听器你还能很快速地过滤出所有断言失败的请求再结合察看结果树看具体的失败响应体。这个组合在长时间压测里特别有用因为跑到后半段系统劣化时断言失败的信息会自动把异常请求挑出来省去了大海捞针的功夫。4. TPS 与响应时间曲线找到拐点就等于找到了瓶颈的线索如果只能选一类监听器来定位瓶颈我会选趋势曲线类。聚合报告是一张合影趋势曲线是一段录像。性能瓶颈几乎总是和时间相关的录像能告诉你问题从哪个时刻开始、当时系统在承受多大的压力这两条信息聚合报告给不了。4.1 活跃线程数、TPS、响应时间三者之间的联动在 JMeter 里线程数代表你施加的并发压力。理想情况下随着活跃线程数增加TPS 会线性增长响应时间保持平稳当系统达到容量上限后再增加线程反而会让 TPS 停滞甚至下降响应时间开始快速攀升。那个TPS 不再增长、响应时间开始抬头的点就是性能拐点也就是瓶颈出现的位置。这个拐点的价值非常大。它告诉你系统当前容量是多少、在什么并发下会出问题也给了你一个量化的扩容指标。比如压测发现 300 个并发时 TPS 不再增长、响应时间翻倍那你在做容量规划时就知道这个服务在目前的配置下单实例合理承载的并发大概就是 300 左右。所以我每次压测都会同时开三个图Transactions per SecondTPS 曲线、Response Times Over Time响应时间曲线、Active Threads Over Time活跃线程数曲线。三张图放在一起看时间轴对齐就能很清楚地还原压测过程中的完整故事。4.2 曲线形态直接指向瓶颈层曲线不只是涨了或跌了它的形态本身就包含信息。我总结过三种最常见的形态曲线形态典型表现大概率指向的瓶颈平滑增长后走平TPS 随并发增长到达某个点后持平响应时间缓慢上升系统到达容量上限常见于数据库连接池、应用线程池等资源到达上限跳水式下降TPS 在某个时间点突然急剧下降响应时间同时飙升触发了熔断、限流或线程池拒绝也可能是缓存失效导致后端被打爆锯齿状波动TPS 和响应时间周期性起伏JVM 频繁 GC、定时任务抢占资源、批处理任务与业务请求互相干扰锯齿状是很多人容易忽略的。有一次我压测一个 Java 服务TPS 曲线每隔一段时间就往下掉一截掉完又恢复。单独看 TPS 还以为是网络抖动后来把服务端 GC 日志拉出来一对比发现锯齿周期和 Full GC 周期完全吻合。这个案例说明曲线形态会给你一个初步的方向但最终的确认必须回到服务端的数据上去。4.3 用时间轴对齐定位问题起点看趋势曲线的时候强烈建议不要只看一张图。正确姿势是把线程数曲线、TPS 曲线、响应时间曲线导出到同一个工具里对齐看或者在 JMeter 里把多个监听器界面并排打开。因为只有时间轴对齐了你才能精确回答这几个问题线程数加到多少时响应时间开始恶化TPS 的下降是先于错误率上升还是后于响应时间的恶化是渐进的还是突变的举个例子。如果活跃线程数曲线平稳上升响应时间曲线也跟着平稳上升TPS 曲线几乎是一条直线说明系统从压力一开始就处理不过来问题可能在应用自身或者数据库。如果线程数平稳响应时间也平稳突然某个时间点响应时间暴涨、TPS 跳水那更像是一个突发事件比如缓存过期、定时任务抢占或者触发了自我保护机制。这两种情况的排查方向完全不同图表组合能帮你很快分辨。5. 进阶用插件曲线定位线程、连接池与队列瓶颈JMeter 自带的监听器画趋势图的能力比较弱真正好用的曲线图基本都来自 jpgc 插件集合。通过 Plugins Manager 安装之后你能拿到一批非常实用的监听器。我用下来最频繁的是下面几个Active Threads Over Time看压测过程中实际活跃线程数随时间的变化。Response Times Percentiles看响应时间百分位随时间的变化能区分长尾请求的走势。Transactions per Second看服务端每秒处理的事务数判断容量和拐点。Connect Times Over Time看 TCP 连接建立耗时用于区分网络层和应用层瓶颈。Response Times Over Time看平均/最大/最小响应时间随时间的变化。PerfMon Metrics Collector采集服务端 CPU、内存、磁盘、网络指标和 JMeter 指标放在同一张时间轴上对比。安装方式不复杂在 JMeter 里通过 Plugins Manager 搜索 jpgc 系列勾选需要的插件重启 JMeter 就生效。注意如果你用的是命令行压测跑完之后需要把生成的 JTL 文件再打开插件监听器会自动读取 JTL 里的数据重新绘制曲线所以不用在压测时开着 GUI。5.1 用线程数与响应时间双曲线缩小排查范围我最常用的一个分析组合是Active Threads Over Time Response Times Over Time。看这两条曲线的相对位置可以快速判断瓶颈到底是被压端的问题还是施压端的问题。操作思路是这样的压测前 1 分钟先把线程数慢慢加上去观察响应时间曲线是否平稳如果在线程数加到 N 之前响应时间一直很稳加到 N 之后开始明显上升那这个 N 就是系统当前配置下的容量边界。接下来去服务端看N 对应的时间点CPU、内存、连接池、线程池哪个指标同时出现了异常就能锁定瓶颈在哪个组件。如果响应时间曲线从压测一开始就高且随着线程数增加越来越差那不是某个并发点上触发了瓶颈而是系统从一开始就处于亚健康状态。这种情况先去查基础配置比如数据库连接池是不是只有 10 个、应用线程池是不是默认值大概率能找到病灶。5.2 连接池和队列瓶颈在曲线上的典型特征连接池耗尽和队列堆积是压测中特别常见的两类瓶颈它们在曲线上的特征有明显区别。连接池耗尽的典型曲线走势是响应时间前期平稳到达某个并发后开始持续爬升同时错误率开始上升错误信息大多是获取连接超时。这类问题在响应时间曲线上表现为平滑的右肩抬升因为每个请求都在排队等连接等得越久响应时间越长。队列堆积的典型走势是活跃线程数已经拉满了TPS 却不再增长甚至下降响应时间大幅增加但错误率不一定高。因为请求都堆积在线程池的队列里排队处理没有超时所以看起来是系统变慢但没报错。这种时候你去查应用线程池的队列长度大概率能看到一个惊人的积压数量。5.3 结合服务端监控才能闭环这里必须反复强调JMeter 图表只能证明瓶颈的存在和大致位置最终的根因确认一定要结合服务端的监控数据。曲线再漂亮也只是外部视角。真正要回答瓶颈在数据库还是应用、是 Redis 慢还是 SQL 慢需要你登录服务器去看 CPU 使用率、内存占用、GC 日志、慢查询日志、连接池状态。PerfMon Metrics Collector 这个插件可以把服务端的 CPU、内存、网络、磁盘指标画到和 JMeter 指标同一条时间轴上。这样一来你就能直接对照响应时间开始上升的那个时刻服务端 CPU 是不是同时到 100%如果两者完全同步那瓶颈就是 CPU 计算密集如果 CPU 没满、响应时间却涨了说明瓶颈更可能在等待型资源上比如数据库连接、锁、IO。这种对照分析能把排查时间缩短一半以上。6. 定位瓶颈的完整实战路径从图表异常到根因确认前面拆了各类图表的用法这一节我把整个排查过程串成一条路径。我自己压测时基本严格按照这个顺序来踩过无数次坑之后发现顺序一旦反了就会白白消耗大量时间。6.1 第一轮先看汇总数据判断有没有问题压测结束后的第一件事是看聚合报告或汇总报告里的四个核心数字Error%、TPS、99% Line、Throughput。如果错误率接近 0、TPS 达到了预期的目标值、99% Line 在业务可接受范围内那这一轮可以判定系统容量满足目标不需要继续往下查。如果其中任何一项不达标就进入第二轮。这里要记录一个关键信息不达标的数据是在什么条件下出现的包括线程数配置、压测持续时间、思考时间设置。没有这个上下文后面的分析很容易走偏。6.2 第二轮看趋势曲线确定问题类型打开 TPS、响应时间、活跃线程数三条曲线重点回答三个问题问题是从压测开始就存在还是到某个并发值才出现指标的劣化是渐进式还是突变式错误率、TPS、响应时间三个指标的变化哪个先发生这三个问题的答案直接决定了你对瓶颈性质的判断。比如TPS 先掉、响应时间后涨和响应时间先涨、TPS 后掉对应的结论完全不一样前者可能是负载均衡把请求分散到了不健康节点后者更像是应用处理能力达到上限。6.3 第三轮结合服务端指标定位瓶颈层级带着趋势曲线给出的方向再去服务端查具体指标。我的排查顺序一般是这样先看 CPU 和内存确认是不是计算资源不够再看磁盘 IO 和网络 IO排除 IO 瓶颈然后看应用线程池和队列状态确认有没有任务积压接着看数据库连接池和慢查询最后看下游依赖Redis、MQ、第三方接口的耗时。这个顺序背后的逻辑是先排除最粗粒度的资源瓶颈再逐步收缩到具体组件。CPU 都 100% 了你就没必要先去查连接池配置连接池都耗尽报错了你也别先怀疑 GC 参数。每排除一层范围就缩小一层。6.4 一个完整的排查案例响应时间突增 90% 等待讲一个完整的案例。一个订单查询接口100 并发压测聚合报告显示平均响应时间从 50ms 涨到了 8sTPS 从 1000 掉到了 80。趋势曲线显示前 2 分钟平稳第 3 分钟开始响应时间直线上升活跃线程数一直没涨满。第一反应是查数据库。但数据库 CPU 只有 20%连接池也没满慢查询日志里最慢的 SQL 也就 300ms。于是转向应用层发现 JVM 内存曲线显示堆内存一直在增长Full GC 从第 3 分钟开始变得非常频繁单次 GC 停顿超过 4 秒。这时再回看响应时间曲线发现响应时间暴涨的时间点和 Full GC 开始的时间完全重合。最终结论是 JVM 堆内存设置过小压测产生的对象把堆撑满导致 Full GC 频繁触发垃圾回收停顿直接拖垮了接口响应。调整堆内存参数后同样 100 并发平均响应时间回到了 60msTPS 恢复到了 950 以上。这个案例的典型之处在于如果不看趋势曲线只看聚合报告你只会得到一个系统很慢的结论完全无法知道慢的原因而如果只看服务端指标你会在数据库、中间件、应用之间来回打转。真正有效的路径是JMeter 曲线发现问题、服务端指标确认根因。7. 监听器使用中的常见坑与个人经验最后聊几个和监听器使用直接相关的坑。这些坑不解决前面的分析方法全都用不上因为你可能根本拿不到可分析的数据。7.1 监听器未启动为什么跑完压测却没有结果这是新手遇到最多的问题之一。在 GUI 模式里编辑脚本时如果只加了线程组和 HTTP 请求跑完了才发现没加任何监听器那所有运行数据都不会保留只能重跑。这个问题的本质是JMeter 的监听器承担了数据采集 结果展示的双重职责不加监听器等于没接记录仪。另一个容易踩的坑是命令行压测。用jmeter -n -t test.jmx -l result.jtl压测时很多人以为指定了-l就够了但注意result.jtl里的数据粒度取决于你在脚本里配置了哪些监听器以及监听器是否配置了输出文件名。如果脚本里没配好采样器保存设置JTL 文件里可能只有汇总数据没有充足的细节供后续绘制曲线。所以建议在脚本里用 Simple Data Writer 或配置好采样器保存策略明确要保存哪些字段、按什么粒度保存。7.2 监听器本身会对压测结果产生干扰监听器不是免费的。打开太多监听器尤其是察看结果树开着跑完整轮压测结果就是压测机自身 IO 和内存被大量占用进而影响施压能力。更隐蔽的是如果把响应全部保存到磁盘磁盘写入本身也会消耗时间导致 JMeter 记录的响应时间偏大。我的建议是调试阶段各种监听器随便开正式压测阶段只保留必要的监听器并关闭结果树用命令行模式跑压测。跑到一半想看实时数据和进度可以再用一个单独的 JMeter 实例打开正在写入的 JTL 文件查看这样不会干扰正在运行的压测。7.3 几个保存和分析结果的小技巧最后分享几个自己常用的实操小技巧把常用的监听器组合保存为测试片段新建一个 Test Fragment放上固定的一组监听器聚合报告、JTL 写入器、常用 jpgc 曲线以后新建测试计划直接拖进来复用不用每次重新配。聚合报告支持导出 CSV压测结束后右键聚合报告选择保存表数据导出 CSV 后再用 Excel 或脚本做二次分析做趋势图、算百分位都比 JMeter 内置界面对比方便。命令行压测时用-e -o生成 HTML 报告JMeter 会生成一个带仪表盘图表的 HTML 报告很多常用图表都自动画好了适合直接发给团队做评审。长时间压测时给每轮结果命名带时间戳的 JTL 文件避免覆盖上一轮的数据方便前后对比。我一般会按接口名_线程数_日期_时间的格式命名。这些技巧看起来不起眼但在实际项目中能省下大量时间。最重要的是它让你手里永远有一份可靠的、可追溯的原始数据这是任何分析工作的前提。
返回列表