ARTICLE DETAIL

资讯详情

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

JMeter+InfluxDB+Grafana:性能测试监控平台搭建实战指南

JMeter+InfluxDB+Grafana:性能测试监控平台搭建实战指南 1. 为什么压测时还得单独搭一套监控聚合报告远远不够大概三年前我第一次独立负责一个订单服务的容量压测脚本写好了线程组也调好了跑了一轮200并发打开JMeter的聚合报告一看响应时间平均320ms错误率0.02%看起来挺健康。但开发同事问我瓶颈到底在哪的时候我哑火了。我只能说出接口平均响应还可以但说不出来是数据库连接池紧张、GC频繁拖慢了响应还是压测机本身CPU被打满了。那个瞬间我就意识到聚合报告解决的是测完之后的统计它不会告诉你压测过程中系统到底经历了什么。这也是性能测试监控平台存在的根本原因把压测过程中施压端指标、被压服务器的资源指标、应用JVM和中间件的运行状态放到同一个时间轴上看缺哪一环就补哪一环。等这套平台搭完你会发现它不仅是压测的辅助工具更是后续性能调优、回归对比、问题定界的基础设施。要学这块的人通常是三类一是正在做性能测试的QA或者测试开发二是想把压测数据沉淀下来的运维三是在准备性能测试面试的工程师——面试官问你如何判断系统瓶颈你直接把监控面板截图丢过去比背一堆概念有说服力得多。1.1 聚合报告只负责事后统计不负责实时定位JMeter自带的聚合报告、Summary Report这类监听器本质上是对整个压测过程做事后汇总。它给的是平均值、中位数、90%线、吞吐量、错误率这些最终结果。问题是压测场景下系统是动态变化的运行到第10分钟GC开始变频繁第15分钟连接池排队第20分钟TPS掉了一半。聚合报告最后只会告诉你平均TPS是800但这800是怎么从1200掉到600的中间经历过几次抖动完全没有过程数据。更麻烦的是分布式压测。当你用多台施压机跑同一个场景每台机器各出一份聚合报告你得手动把它们合并、对齐时间窗口累得半死还容易算错。我后来用监控平台直接看整合曲线再也不想回去手动算那玩意了。1.2 一套能落库、能告警、能复盘的结构到底要解决什么具体来说监控平台要解决三件事关联把施压端的TPS、响应时间、错误率和被压服务器的CPU、内存、磁盘、网络以及应用的GC、线程数放到同一时间维度。这样才能回答TPS掉的时候是机器资源不够还是应用自己出了问题。留存压测结束后数据落库任意时间范围都能拉出来复盘。今天发现某个接口性能劣化可以直接回头对比上周同一场景的曲线。实时告警压测执行中自动判断指标是否异常比如响应时间突然超过基线、错误率抬头、机器资源被打爆及时提醒调整负载或暂停压测。这套能力和标准的性能测试流程是绑在一起的。常规的jmeter性能测试步骤无非是明确指标需求、写好脚本、设计场景、执行压测、分析结果、调优再验证。但第5步分析结果如果只看聚合报告基本只能靠猜。监控平台补的就是第4、5步之间那段空白——执行过程中有哪些过程指标、系统状态如何变化全部直观呈现。2. 组件选型对比InfluxDB这套组合是怎么定下来的说到搭建第一关就是选型。性能测试监控平台的方案不算少但真正落地稳定的就那么几种。我最终用的是JMeter自带BackendListener InfluxDB Telegraf Grafana的组合下面把为什么这么选讲清楚。2.1 主流方案横向对比市面上比较常见的方案大概有四类我根据自己的使用体验整理了一个对比方案优势需要注意的点典型场景JMeter BackendListener InfluxDB Telegraf Grafana官方原生支持几乎零侵入组件轻量模板成熟InfluxDB集群版收费单机足够需要自己维护一张时序表结构绝大多数中大型压测平台自建Prometheus jmeter-prometheus-plugin node_exporter Grafana拉模式服务发现好云原生生态强告警体系完善JMeter对接需第三方插件小众插件维护风险拉模式对临时启停的压测机要额外处理已有Prometheus体系的团队商业云压测平台如PTS、LoadRunner SiteScope开箱即用自带全套报表成本高数据落地格式不透明二次开发受限企业预算充足、追求省事全自研采集系统灵活可控指标口径完全自定义开发量大序列化、队列、存储、展示全得自己搞有专门测试平台研发团队的大厂对比下来InfluxDB这套方案是投入产出比最高的。JMeter原生就带InfluxDB的BackendListener实现类不需要往脚本里塞额外的jar包或者改采样器代码Grafana官方的模板库里也有JMeter相关的现成面板可以导入。2.2 我为什么没有选Prometheus生态这里要正面聊一下Prometheus因为它确实是很多人的第一反应毕竟K8s和云原生环境下Prometheus几乎是标配。但放在压测监控这个场景里有几个麻烦点压测机的生命周期是短时、频繁启停的。Prometheus是拉模式要靠服务发现找到target压测机每次启动后如果IP变了或者抓取周期和压测机启动时间错开就会产生抓空窗口。JMeter要对接Prometheus目前主流是社区插件jmeter-prometheus-plugin虽然能用但更新节奏一般版本和JMeter大版本容易不兼容。如果团队之前没接触过PromQL学习成本明显比InfluxQL要高一点。不是说Prometheus不能用而是对于一开始只为了把压测数据看明白的团队InfluxDB这条链路更顺。另外InfluxDB 1.8单机版非常轻量一个二进制文件就能跑数据保留策略写起来也简单这对我这种不想维护一堆组件的人来说很友好。2.3 整体架构和数据流这套方案的架构很清晰压测机JMeter BackendListener -- InfluxDB 被压服务器1Telegraf -- InfluxDB 被压服务器2Telegraf -- InfluxDB Grafana数据源InfluxDB -- 展示 告警JMeter在跑压测时通过BackendListener定时把聚合指标写入InfluxDB每台被压服务器上部署Telegraf采集CPU、内存、磁盘、网络这些系统指标也写入同一个InfluxDBGrafana连接InfluxDB数据源做成实时面板。这里有一个部署层面的建议监控组件InfluxDB、Grafana一定单独部署不要放在被压服务器上也别和压测机混用。监控组件本身有IO和网络开销混在被压环境里会污染压测结果。我自己吃过这个亏刚开始图省事把InfluxDB装在被压的应用服务器上结果压测时应用和数据库抢磁盘IO数据一路漂移排查了大半天才意识到是监控自己捣的乱。3. BackendListener配置和指标格式压测数据是怎么进时序库的这一章是实操的重点。搞清楚JMeter的BackendListener到底怎么把数据送入InfluxDB后面排错会省很多力气。3.1 BackendListener在JMeter内部干了什么JMeter在压测过程中每一次SampleResult产生后都会触发结果监听。BackendListener就是官方提供的异步上报扩展点它在后台用一个独立的线程池接收SampleResult按你配置的粒度做聚合计算比如每5秒聚一次然后把聚合后的指标通过HTTP API批量写到InfluxDB。可能你会想直接在JSR223后置处理器里把结果打到日志再用Logstash解析不是也行吗能行但很蠢。BackendListener的好处是聚合逻辑官方写好了批量上报的缓冲和并发控制也考虑好了还支持通过samplersRegex过滤只上报哪些事务。你只需要填配置不需要自己维护一套数据采集代码。3.2 具体配置步骤在JMeter中打开测试计划选中测试计划节点右键Add - Listener - Backend Listener然后在界面里配置。重点参数如下表参数示例值说明Backend Listener implementationorg.apache.jmeter.visualizers.backend.influxdb.InfluxdbBackendListenerClient官方InfluxDB实现类influxdbUrlhttp://192.168.1.10:8086/write?dbjmeterInfluxDB的HTTP写入地址注意IP必须是压测机能访问到的applicationorder-service被测应用标识会作为tag写入measurementjmeter数据表名默认就是jmetersummaryOnlyfalse设为false才会按事务维度分开记录true就只记录整体samplersRegex.*匹配要上报的采样器名useRegexForSamplerListtrue是否用正则匹配percentiles99;95;90需要计算哪些响应时间分位数配置之前先在InfluxDB里把库建好。我实际用的是InfluxDB 1.8命令如下influx CREATE DATABASE jmeter WITH DURATION 30d REPLICATION 1 NAME jmeter_30dWITH DURATION 30d的含义是数据自动保留30天后面就不用担心存储无限膨胀。然后还要给Telegraf建一个库CREATE DATABASE telegraf我强烈建议在库名和保留策略上分清压测指标和服务器的系统指标分开存放。虽然可以放到同一个库用tag区分但实际使用时你会发现查询和管理都不方便分库更清爽。3.3 InfluxDB里到底长什么样配置好之后压测一跑InfluxDB就会收到类似这样的数据点jmeter,applicationorder-service,transaction查询订单,statusok avg12.5,min8,max45,count1024,errors0,pct9523.4,hits204.8这行叫Line Protocolapplication、transaction、status是tag用于筛选avg、min、max、count、errors、pct95、hits这些是field存储具体数值。其中关键字段我解释一下count是时间窗口内的请求样本数hits是吞吐量也就是每秒钟的事务数画TPS曲线基本靠它pct95/pct99是响应时间的95分位和99分位比avg更能暴露长尾问题errors是错误发生次数结合count算错误率。把这些字段理解清楚后面写Grafana查询的时候会非常有底气。4. Grafana面板设计怎么把压测过程看明白数据进来了下一步就是让它变成一眼能看懂的曲线。Grafana面板不需要一开始就做得花哨先把最核心的几个视图做出来。4.1 压测核心指标面板我每次压测必看的面板有四个TPS趋势整个压测的吞吐量变化看有没有抖动、掉顶、平台期。响应时间曲线把avg、p95、p99叠在同一张图上观察是否有飙升或锯齿。错误率曲线errors/count换算成百分比。吞吐和线程联动如果分布式压测每台施压机的TPS可以合在一起看。画TPS曲线时Grafana查询可以这样写SELECT sum(hits) FROM jmeter WHERE (application ~ /^$application$/) AND $timeFilter GROUP BY time($interval), transaction这里的$application是Grafana的模板变量定义时可以查InfluxDB里的tag值SHOW TAG VALUES FROM jmeter WITH KEY application$transaction同理。用模板变量的好处是切换应用或者只看某个事务的时候只需要在面板顶部改下拉框不用重新编辑查询。响应时间面板的查询类似SELECT mean(pct95) FROM jmeter WHERE (transaction ~ /^$transaction$/) AND $timeFilter GROUP BY time($interval)我通常会把p95和p99放在一张图里两条线的间距越拉越大说明长尾响应在恶化。4.2 服务器资源面板与JVM监控施压端指标只反映现象要定位原因得看被压服务器的状态。Telegraf默认就会采集CPU、内存、磁盘、网络、系统负载这些核心指标它在InfluxDB里自动创建对应的measurement如cpu、mem、disk、net、system。CPU使用率我用的查询是这样SELECT 100 - mean(usage_idle) FROM cpu WHERE (cpu cpu-total) AND $timeFilter GROUP BY time($interval)内存使用率SELECT mean(used_percent) FROM mem WHERE $timeFilter GROUP BY time($interval)磁盘使用率SELECT max(used_percent) FROM disk WHERE $timeFilter GROUP BY time($interval)网络速率需要用导数换算SELECT non_negative_derivative(mean(bytes_recv), 1s) FROM net WHERE $timeFilter GROUP BY time($interval)JVM监控这部分我推荐用Telegraf的jolokia2_agent插件。前提是被压应用的JVM开启Jolokia端点通常是启动参数加-javaagent:jolokia-jvm.jar然后在Telegraf里配置GC相关MBean。下面是关键配置片段[[inputs.jolokia2_agent]] urls [http://192.168.1.20:8080/jolokia] [[inputs.jolokia2_agent.metric]] name java_gc mbean java.lang:typeGarbageCollector,name* paths [CollectionTime, CollectionCount]为什么一定要盯GC因为Full GC频繁会让应用的响应时间出现规则的锯齿形尖刺这个现象单看JMeter的avg可能不明显但看P99会非常扎眼。有一次我们排查接口偶发卡顿就是靠GC面板发现Old GenGC每秒都在触发才顺藤摸瓜找到堆配置太小的问题。面板布局上我习惯把施压端TPS和服务器CPU放在上下两个图里并且保持相同的时间范围。这样一眼就能判断TPS掉的时候CPU有没有同步变化。如果CPU没有变化说明瓶颈不在机器资源而在应用内部比如线程池、数据库连接池。4.3 不同压测场景的看点差异常见的性能测试类型有三种每种场景监控的重点不一样容量测试核心看TPS曲线什么时候不再增长、响应时间在哪个并发点开始拐头。这就是所谓的拐点分析也是性能测试面试题里高频出现的如何判断系统最大容量的实现方法。稳定性测试看长时间运行下的内存走势、Full GC频率、错误率是否逐渐累积。内存曲线持续缓慢上升基本可以判断有内存泄漏。峰值/突发测试看错误率峰值、恢复时间、队列积压情况。面试的时候如果被问到性能测试关注哪些指标你把TPS、RT的P95/P99、错误率、CPU、内存、GC这几个指标连同为什么看它们一起说出来已经是满分答案了。而这里搭好的平台就是你回答时最好的底气。5. 告警规则设计从量纲到误报抑制面板是给人看的但压测经常是夜间长跑你不能整晚盯着屏幕所以告警必须配好。Grafana 8之后内置了完善的告警引擎直接可以基于InfluxDB查询出规则。5.1 为什么固定阈值在压测场景下会误报很多从运维告警过来的同事第一反应是设阈值比如CPU超过80%就报警。这在压测场景里是完全行不通的——压测本来就是故意把系统往极限逼CPU跑到90%以上恰恰说明你加压成功了这时候报CPU高毫无意义。所以压测告警的核心思路不是绝对值报警而是异常劣化报警。5.2 我实际在用的告警思路我实际落地的规则大概是这样的响应时间劣化告警取最近一轮同场景压测的P95值作为基线当前P95超过基线的1.5倍持续60秒触发Warning超过2倍持续120秒触发Critical。错误率突增告警错误率绝对值大于0.1%持续30秒触发Warning。资源异常联动告警CPU使用率高于95%且TPS同时出现下跌趋势此时说明系统已经进入资源饱和、吞吐下降的状态需要人工介入确认是瓶颈还是故障。最后一条是我觉得最实用的。纯看CPU没意义但要结合TPS的走势就能把正常加压和系统崩溃区分开。Grafana告警规则的查询要注意一点告警评估不支持模板变量你新建规则时不能直接复用面板带$application的查询要把变量替换成固定的查询条件。比如SELECT mean(pct95) FROM jmeter WHERE (application order-service) AND time now() - 5m GROUP BY time(10s)然后设置条件查询结果超过某个阈值持续N次触发。5.3 告警通知与抑制通知渠道上我用的Grafana Alerting自带的Webhook打到企业微信/钉钉机器人。规则分两级Warning只发到压测执行群提醒关注。Critical会额外触发电话或者值班盯屏因为压测现场数据崩坏可能不只是性能问题而是环境故障。最容易被忽略的是告警抑制。当被压服务器宕机时上面所有接口的告警会同时触发几十条消息刷屏。所以要在通知策略里按标签分组让同一个服务器相关的告警合并成一条消息通知。这样既不会漏关键信息又不会被轰炸到麻木。6. 上线后的踩坑复盘数据错位、丢点和存储膨胀平台搭起来只是开始真正闹心的是用着用着发现数据不对。这一章我把踩过的几个坑和排查思路完整复盘一遍你可以直接照着避。6.1 时间轴对不上时区与聚合窗口第一个让我头大的问题是Grafana里看到的TPS峰值曲线比压测实际执行时间偏移了几分钟。一开始我还以为是网络延迟后来排查发现是时区问题。InfluxDB默认以UTC存储时间戳如果压测机、InfluxDB服务器、Grafana所在机器的系统时区不一致出来的时间轴就会错位。排查链路是这样的先在InfluxDB里用select * from jmeter order by time desc limit 10看数据点的实际时间戳对比压测机的系统时间然后确认Grafana的时区设置。最后的解法是所有压测机、监控机统一用UTCGrafana面板时区也固定成UTC反正压测报告里的时间窗口本来就是人为约定的统一就好。6.2 丢点与缺数据上报链路和线程池抖动用了一段时间后我发现TPS曲线时不时会出现掉到0又弹起来的毛刺。一开始以为是被压应用真的挂了检查应用日志发现好着呢再查发现是监控数据丢点。原因有两类一是压测机和InfluxDB之间的网络有抖动HTTP写入超时二是JMeter在高压场景下主线程的全量GC会拖慢BackendListener的异步发送线程导致数据在缓冲池里积压后被丢弃。排查思路是先看InfluxDB的写入日志有没有超时记录再看JMeter的日志里BackendListener有没有报错同时把InfluxDB的HTTP写入超时时间和JMeter的influxdbMaxBatchSize参数调大。如果是公司内网可以适当放宽超时但跨公网写InfluxDB这种设计从一开始就该避免。实在不行加一层本地的Telegraf做缓冲转发也比直接裸写更稳。6.3 存储膨胀和高基数问题长跑几轮稳定性测试之后我发现InfluxDB的磁盘占用增长快得吓人。查下来是三个原因叠加没设保留策略数据全攒着面板默认按1秒粒度刷新查询实际上采样数据本身并没有那么密事务的标签基数太大——比如把每次压测的请求参数拼到了事务名里导致transaction这个tag有几千上万个唯一值索引直接爆炸。解决办法我整理成了三条你直接照做建库时指定DURATION 30d超期数据自动清理。Grafana面板最小时间间隔设置成10秒或者30秒别让查询去撞1秒级粒度。在JMeter的samplersRegex里只保留有限的业务事务把事务名统一规范别让动态参数进事务名。6.4 告警没触发模板变量和固定查询的坑有一次我自信满满地配好了告警结果压测时错误率都冲到5%了告警一声不吭。排查了半天发现原因是告警规则的查询条件是之前从面板查询直接复制过来的里面带着$application和$timeFilter这些模板变量。在面板里浏览器会帮你替换变量但告警规则在后台独立评估根本识别不了模板变量等于查了个无效的查询条件自然不会触发。从那以后我总结了一条规矩凡是给告警用的查询必须是一个不依赖模板变量的、完整的固定条件查询单独写不和面板查询混用。这个坑非常有隐蔽性因为告警规则编辑页里你看到的查询是能正常返回数据的用了变量它也看起来没问题实际评估时却是另外一回事。希望看到这里的朋友不会再花一个晚上去查这个。最后说点个人体会。这套监控平台搭完之后对我工作方式最大的改变不是曲线好看了而是压测报告终于能讲出故事了开发问你TPS为什么上不去你把TPS和CPU、GC曲线叠在一起的截图发过去对方自己就能判断该查代码还是查配置。对几百并发以下的中小型项目来说这套方案的组件开销很小但收益非常直接。如果你刚开始搭我的建议是先跑一个最小可行版本一台InfluxDB、一个Grafana、JMeter里加一个BackendListener把聚合报告替换成监控面板先跑通一轮压测。然后再逐步加Telegraf、JVM面板和告警。别一上来就追求大而全容易把自己劝退。另外提醒一句第一次搭完先拿面板上的TPS总和和聚合报告里的总事务数对一下确认采集链路没丢数据再放心去信任那些曲线。
返回列表