ARTICLE DETAIL

资讯详情

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

JMeter+Prometheus+Grafana:打造压测实时监控链路

JMeter+Prometheus+Grafana:打造压测实时监控链路 我最早做压测时最头疼的就是压完才看聚合报告。跑一次一小时的压力测试中途完全不知道服务是不是已经打挂了CPU是不是早就飙满接口响应时间是不是已经涨了十倍。直到我把 JMeter、Prometheus、Grafana 三个开源工具串成一套实时监控这个问题才彻底解决。这套组合完全是业界成熟方案没有自己写一行业务代码只靠配置就能把压测过程中的吞吐量、响应时间、错误率、线程运行状态全部可视化出来还能和历史数据对比。这篇内容不是教科书式的工具介绍是我自己从零搭建、踩坑、调优后沉淀下来的一套可复现流程。无论你是刚接触性能测试的测试工程师还是要做全链路压测的运维/开发照着下面的步骤操作两小时以内就能跑通一条“JMeter 压测 → Prometheus 采集 → Grafana 展示”的完整链路。后面还会把我遇到过的几个典型坑一并列出来帮助你少走弯路。1. 为什么要做这套监控从“黑盒压测”到“实时可观测”1.1 压测只看聚合报告到底缺了什么JMeter 自带的聚合报告Aggregate Report和结果树View Results Tree是大家最常用的功能但它们都有个共同问题信息滞后。压测过程中你只能看到一个数字慢慢涨等跑到一半发现 TPS 掉了想去定位是脚本问题还是服务问题能查的线索非常有限。更麻烦的是结果树如果开着JMeter 自身会积累大量请求对象导致施压机内存暴涨压出来的数据本身就不准。这时候我们需要的是“边压边看”的能力。压测过程中每隔几秒就能看到当前平均响应时间、错误率、请求数、网络吞吐量最好还能把压测机和目标服务器的系统指标放在同一个时间轴上比对。JMeter 本身不提供实时仪表盘但它提供了 BackendListener 接口允许把压测指标周期性地发送到外部监控系统。这就是我们常说的“JMeter 可视化监控”的组合由来。1.2 三种工具如何分工数据流是什么样的这套方案里三个工具的职责非常清晰JMeter负责产生压测流量同时通过一个插件把采样器Sampler的统计数据暴露成一个 HTTP 接口格式是 Prometheus 能识别的文本指标格式。Prometheus按照固定时间间隔去拉取这个接口把指标存成带时间戳的时序数据并附上 job、instance 等标签方便后续筛选。Grafana负责接 Prometheus 数据源把时序数据画成可视化的折线图、仪表盘、热力图并且支持告警规则。整个数据流就是JMeter 指标 → Prometheus 抓取 → Grafana 展示。也没有中间件需要维护三个进程看起来是独立的但逻辑上环环相扣。我一开始也考虑过用 InfluxDB Grafana 的方案最后还是选了 Prometheus理由很直接Prometheus 生态更通用不只是压测监控能复用以后服务监控、数据库监控、K8s 监控都能用同一套底座学习成本一次投入长期受益。而且 Prometheus 的拉模式Pull对压测场景很友好JMeter 不需要主动推数据数据链路少一个环节故障定位就更简单。2. 工具版本选择与安装准备2.1 版本规划与端口约定这类开源组件版本迭代特别快不同版本间配置语法可能会有差异。我搭建时用的组合是组件推荐版本依赖环境默认端口JDK8 / 11 / 17根据 JMeter 版本选择--Apache JMeter5.5 或 5.6.xJDK 8无固定端口jmeter-prometheus-plugin0.6.2 或最新 releaseJMeter 5.x9270插件暴露Prometheus2.45.0 或更新-9090Grafana9.x / 10.x / 11.x-3000端口规划提前想清楚能省很多事。JMeter 插件暴露指标的口径是 9270Prometheus 自身 Web UI 是 9090Grafana 是 3000。如果你用 Docker 部署主机端口和容器端口都要放开别把容器内部的 9090 映射到宿主机的其他端口虽然也可以但增加记忆成本。如果是在公司内网搭测试环境还需要确认防火墙有没有把这三个端口放通尤其是 JMeter 那台机器很多时候 Prometheus 抓不到数据问题出在 Windows 防火墙拦了 9270 端口。2.2 JMeter 安装与插件部署JMeter 安装本身没什么技术含量去 Apache 官网下载二进制包解压配置好 JAVA_HOMEWindows 下双击 jmeter.batLinux/macOS 下运行 jmeter.sh。这里我只强调一个容易被坑的点JMeter 是 Java 应用它不用安装但是 JDK 版本必须匹配。JMeter 5.6 官方文档写的很明确要求 Java 8 以上但实测下来如果你用的是 JDK 17一些老插件可能不兼容如果你还在用 JDK 7那直接跑不起来。建议统一用 JDK 11兼容性最稳。下一步是装 prometheus 监听器插件。我用的插件是 GitHub 上开源项目 jmeter-prometheus-plugin作者是 ldiego实际仓库地址是 dolphyfan/jmeter-prometheus-plugin它的原理就是利用 JMeter 的 BackendListener 扩展点在压测过程中定时把统计数据聚合成 Prometheus metrics 格式。安装方法很简单到项目 Releases 页面下载对应 JMeter 5.x 的 jar 包。把 jar 放到 JMeter 解压目录的lib/ext目录下。完全退出 JMeter重新启动。这个插件不像 JMeter Plugins Manager 里的东西没有 UI 管理入口所以安装完不会看到任何新菜单很多人会怀疑装没装上。检测方法很简单新建一个测试计划添加一个 Backend Listener看实现类下拉列表里有没有以io.github.ldiego.simplemetrics开头的选项或者直接在里面输入PrometheusListener。如果列表里有说明插件加载成功了。如果看不到八成是 JMeter 版本和插件版本不匹配或者 lib/ext 下同时存在了两个版本的插件 jar出现了类加载冲突。2.3 Prometheus 和 Grafana 的安装方式Prometheus 安装同样很简单官方提供了 Linux 二进制包和 Docker 镜像。我日常测试环境喜欢用二进制方式因为配置文件改起来直观排障时 tail 日志也方便。# Linux 下解压并运行 wget https://github.com/prometheus/prometheus/releases/download/v2.45.0/prometheus-2.45.0.linux-amd64.tar.gz tar zxvf prometheus-2.45.0.linux-amd64.tar.gz cd prometheus-2.45.0.linux-amd64 ./prometheus --config.fileprometheus.yml启动后浏览器访问http://localhost:9090能看到 Prometheus 自带的简易查询页面就说明服务起来了。Grafana 我建议直接 Docker 起数据量不大也不涉及复杂持久化配置docker run -d -p 3000:3000 --namegrafana -e GF_SECURITY_ADMIN_PASSWORDadmin grafana/grafana:10.4.0第一次登录默认账号是 admin/admin它会提示你修改密码。如果你不想每次手动起服务可以用 systemd 或 docker-compose 固定成常驻服务。这个阶段出现问题的概率不高如果端口被占用调整映射端口就行但后面配置 Grafana 数据源时 URL 要和映射端口保持一致。3. 核心配置打通 JMeter 到 Grafana 的数据链路3.1 JMeter 侧Backend Listener 配置这是整套方案最核心的一步。打开 JMeter在测试计划上右键 → 添加 → 监听器 → Backend Listener。实现类选择io.github.ldiego.simplemetrics.PrometheusListener然后配置参数。插件默认参数有几个值得单独说明参数作用我的推荐值metricsPort插件启动时绑定的 HTTP 端口供 Prometheus 拉取9270reportingIntervalSeconds指标聚合上报周期单位秒5 或 10prefix指标名前缀方便区分不同测试计划测试计划名如jmeter_demobuckets响应时间直方图分桶用于计算 P90/P95默认值即可我真的翻过很多帖子发现不少人在这个 Listener 上选错了实现类选了 GraphiteBackendListenerClient然后填了一堆 Graphite 的配置折腾半天数据还是进不了 Prometheus。要记住如果要用 Prometheus 方案选的就是这个以PrometheusListener结尾的实现类。它内部会启动一个轻量级 HTTP Server访问http://localhost:9270/metrics就能看到一大串以jmeter_开头的指标比如jmeter_test_requests_count 15230 jmeter_test_mean_elapsed_time 128.45 jmeter_test_errors_count 3 jmeter_test_max_elapsed_time 1024.88 jmeter_test_stddev_elapsed_time 58.32这里有个细节reportingIntervalSeconds设得越小曲线越平滑但 JMeter 和 Prometheus 的压力都会增大。设得太大一旦中间发生故障监控数据丢失的就越多。我压测时一般设 5 秒既能看到实时趋势也不会给施压机带来明显负担。需要注意压测结束前 JMeter 不会主动推最后一批数据到 metrics 接口所以结束压测后面板可能会缺最后几秒的曲线这在可视化里是正常的不要误以为是系统挂了。3.2 Prometheus 侧抓取任务配置Prometheus 采用 Pull 模型定时访问 JMeter 暴露出来的 metrics 接口。修改 Prometheus 安装目录下的prometheus.yml在scrape_configs下新增一个 jobglobal: scrape_interval: 5s evaluation_interval: 10s scrape_configs: - job_name: jmeter_test metrics_path: /metrics static_configs: - targets: [192.168.1.10:9270] labels: scenario: demo-testscrape_interval我故意设成 5 秒和 JMeter 的上报周期保持一致这样 Prometheus 通常能抓到每条最新指标。如果 JMeter 上报周期是 10 秒Prometheus 抓取间隔还是 5 秒会抓到大量重复值浪费存储但展示上问题不大。反过来如果 Prometheus 抓取间隔比上报间隔大比如抓取间隔 15 秒、上报 5 秒那么曲线会变得粗糙虽然还能看出趋势但 P95 这些瞬时值会失真。targets里的 IP 一定要写 Prometheus 能从网络访问到的地址。如果你在 Linux 上用 Docker 跑 Prometheus然后把 targets 写成localhost:9270那 Prometheus 容器里的 localhost 指的是容器自己不是宿主机必挂。这种场景要么用--networkhost跑容器要么写宿主机局域网 IP。另外 Prometheus 的 yml 只认 UTF-8 编码Windows 记事本编辑容易引入 BOM 头最好用 VS Code 或 Notepad 改完再保存。配置改好后重启 Prometheus打开http://localhost:9090/targets如果新增的jmeter_testtarget 状态是 UP说明链路前半段已经通了。这一步是分水岭很多人的问题都出在这状态不是 DOWN 就是 unknown那后面 Grafana 怎么配都是白搭所以建议先在这里多花两分钟确认。3.3 Grafana 侧数据源与仪表板导入Prometheus 的数据进来了Grafana 的活就轻松了。打开 Grafana左侧菜单 → Connections → Data sources → Add data source选择 PrometheusURL 填http://localhost:9090点击 Save Test看到绿色的返回信息就说明数据源连接成功。接下来是有两种方式出面板。一种是手动创建 Panel每个 Panel 写 PromQL 查询灵活性最强另一种是直接导入现成的 Dashboard 模板导入后改一下数据源就行适合快速搭建。我个人推荐先用现成模板把链路跑通再逐步改成自己团队习惯的样式。用模板时我建议直接用插件仓库自带的grafana_dashboard.json。在 jmeter-prometheus-plugin 的 GitHub 仓库里有个grafana/dashboards目录里面有官方给出的仪表板定义里面包含吞吐量、响应时间、错误数、线程数等常用 Panel。下载后在 Grafana 里 Dashboards → Import → Upload dashboard JSON file 上传即可。如果你不想去翻仓库也可以在 Grafana 官网 Dashboards 市场搜索jmeter挑一个 Star 数高的导入比如常被用的 ID 5496 就是 JMeter 监控模板。导入时注意选择你已经配置好的 Prometheus 数据源否则模板里的指标全显示成 No data。手动创建的思路也顺便提一下。新建 PanelPromQL 查询示例# 请求数/STPS sum(rate(jmeter_test_requests_count[1m])) # 平均响应时间单位毫秒 jmeter_test_mean_elapsed_time # 错误率 sum(rate(jmeter_test_errors_count[1m])) / sum(rate(jmeter_test_requests_count[1m]))这里有个大坑插件不同版本对指标名命名不一致有的叫jmeter_test_requests_count有的叫jmeter_test_requests_total还有的带上了_seconds后缀。所以在你写 PromQL 前先到 Grafana Explore 页面输入jmeter_看自动补全的指标列表里到底有哪些指标名再抄到查询里去。我刚开始就是拿着老博客的指标名一路抄结果 Panel 上永远没数据后来一查才发现是新版插件指标命名加了_total前缀。花几分钟探一下真实指标名省得后面一个 Panel 一个 Panel 地排错。4. 完整实操从零搭建一套压测监控4.1 准备一个最小压测脚本不要一上来就压线上业务先用一个本地接口或者公网稳定性高的站点练手。我自己验证环境时常打http://www.example.com虽然国外站点延迟高但不至于轻易打挂自己的机器。在 JMeter 里创建如下元素线程组线程数 100Ramp-Up 时间 10 秒循环次数 10。HTTP 请求协议 http服务器地址填入 target host路径 /。添加断言响应代码等于 200 或者响应内容包含某个关键字确保请求不是全部报错还看起来很正常。添加 Backend Listener按 3.1 节的参数配置。这里我提供一个额外提醒压测时一定不要勾选结果树监听器。结果树会把每个请求的响应内容存在内存里100 并发跑 10 分钟JMeter 内存直接爆掉压测数据也会因为 Full GC 而抖动。看监控面板比看结果树快得多也准得多。4.2 启动链路与验证步骤按顺序启动组件顺序其实无所谓但验证问题时最好有个标准流程启动 JMeter开始压测。浏览器访问http://localhost:9270/metrics确认能看到带jmeter_前缀的指标。访问 Prometheushttp://localhost:9090/targets确认 target 状态是 UP。在 Prometheus Graph 页面执行一句最简单的查询比如jmeter_test_requests_count确认有时间序列返回。打开 Grafana看面板是否出现曲线。我每次排障都按这个顺序来一步不通就卡在那一步不要跳着猜。比如远端 Prometheus 里查得到指标、Grafana 里没数据那基本就是 Grafana 数据源配置或者 Panel 查询问题如果 Prometheus 里也查不到那问题一定出在 JMeter 暴露接口或 Prometheus 抓取配置上。4.3 面板关键指标的读法面板不是拉几张图就完事的关键是读得懂。我常用的几个指标维度TPS / 吞吐量看rate(jmeter_test_requests_count[1m])或对应指标。它有明显的上升期、平稳期、下降期如果曲线在压测中段出现断崖下跌优先怀疑服务端瓶颈或网络问题而不是脚本问题。平均响应时间配合线程数看如果线程数线性上升但响应时间同步飙升说明系统容量已经到达临界点。错误率JMeter 指标里以jmeter_test_errors_count为准计算时要除以请求总数。错误率如果和响应时间同步上升那很可能是服务端开始拒绝请求或超时。P90/P95新版插件带直方图指标时可以用 histogram_quantile 计算比如histogram_quantile(0.95, sum(rate(jmeter_test_elapsed_time_bucket[1m])) by (le))P95 比平均值更能暴露尾部延迟问题。比如平均响应时间只有 120ms但 P95 已经到了 1 秒那就说明有近 5% 的请求明显偏慢这个对用户体验影响是很直接的。只看平均值做性能结论是很常见的误区。5. 常见问题与排查技巧实录5.1 数据链路不通从端口到 target 状态先说最容易遇到的一类问题Prometheus 的 target 状态一直是 DOWN。这种问题通常分几种原因端口不通在 JMeter 机器上用curl http://localhost:9270/metrics看接口是否返回如果本机通、远端不通就是防火墙或安全组问题。Windows 上很常见需要主动放行 Java 进程或 9270 端口的入站规则。targets 写错前面说过 Docker 里的 localhost 坑以及 IP 地址抄错的问题。JMeter 没真正启动监听如果 Backend Listener 配置完成但没保存测试计划或者 JMeter 进程挂起导致端口没监听也会出现 DOWN。这种情况直接在 JMeter 机器上 netstat 一下 9270 端口最直接。还有一个不常见但很隐蔽的情况JMeter 以 GUI 模式跑时你可能在脚本里配了 Backend Listener但没等它完全初始化就点了开始这时候端口监听稍慢一些Prometheus 第一次抓取失败后不会重试。遇到这种把抓取间隔调大一点多等十秒再看 target 状态。5.2 指标为空的排查逻辑指标名对不上Prometheus target 状态 UP但 Grafana 面板全是空白这个场景大家肯定都见过。我排查时第一件事就是去 Grafana Explore 里执行jmeter_开头的自动补全看看实际有哪些指标名。这里遇到的坑主要是插件版本升级导致的指标名变化比如有的版本是jmeter_test_requests_count有的版本是jmeter_test_requests_total还有的自定义 prefix 没生效导致指标名带了额外前缀。优先以实际返回的指标名为准别盲目照抄网上旧配置。其次Grafana 面板的时间范围如果选的是 last 1 hour而压测只跑了 5 分钟曲线显示不出来也很正常可以切到 last 15 minutes 或 last 5 minutes 再看。5.3 面板报错与数据源 UID 问题Grafana 从 9 升到 10 或 11 之后打开旧面板偶尔会看到类似failed to upgrade legacy queries datasource im7_otuvz was not found的报错。这个报错并不是数据源丢了而是面板 JSON 里写死的 datasource uid 和当前 Grafana 元数据不匹配导致查询无法自动升级。我处理这类问题有两条路在数据源设置里复制当前 Prometheus 数据源的 UID。进入 Dashboard JSON 模型全局搜索旧 UID替换为新 UID保存后重新打开面板。如果旧数据源已经不见了那就新建一个 Prometheus 数据源记下新的 UID再替换进面板 JSON 里。替换时建议先备份 JSON毕竟面板内容多手滑改坏了方便回滚。5.4 压测结束后的数据尾巴和性能干扰压测结束后面板曲线戛然而止这不是故障是 Prometheus 拉不到新指标了。有些人在压测结束后看到曲线断开会误以为监控挂了实际上是正常的结束边界。如果你希望曲线更平滑地收尾可以在压测结束前让线程组进入“平稳递减”模式或者加一个持续控空的请求周期。不过在实际业务里压测停止就是瞬间停止真实观测边界更重要。另外压测过程中如果还有 JMeter 自带的聚合报告监听器在跑或者结果树开着都会影响施压机性能。插件的指标上报是异步的但它只是轻量 HTTP Server本身影响不大。真正影响 JMeter 的是在压测时打开 GUI 监听器、存取大量响应数据。压测机尽量用命令行非 GUI 模式启动脚本里只留必要断言和后端监听器这样施压机资源才能全部给到压测流量上。6. 优化建议与扩展方向6.1 抓取频率与数据存储的权衡Prometheus 默认抓取频率是 15 秒对常规服务监控够用但对压测这种短时间高动态场景来说15 秒太粗了建议调成 5 秒。同时storage.tsdb.retention.time控制数据保留时长默认是 15 天。压测数据如果只是临时看15 天足够如果要长期做趋势对比建议开启 Prometheus 的远程存储或者定时把面板截图归档到工单系统。抓取频率短会导致 Prometheus 本地 TSDB 文件增长加快但压测场景一般只持续几十分钟到几小时整体数据量并不大这个压力可以忽略。真正需要注意的是 JMeter 插件上报间隔和 Prometheus 抓取间隔尽量保持一致否则会产生大量重复序列浪费存储空间。6.2 多机压测与系统监控指标单机压测是最基础的形式但真实的全链路压测往往有多个施压节点。每个节点上的 JMeter 都会暴露 9270 端口Prometheus 的 scrape_configs 里配置多个 targets 即可scrape_configs: - job_name: jmeter_test static_configs: - targets: - 192.168.1.10:9270 - 192.168.1.11:9270 - 192.168.1.12:9270这样 Grafana 面板上就能按 instance 标签区分每个施压节点的数据。更进一步的实用思路是在所有施压机和目标服务器上装 node_exporter把 CPU、内存、磁盘、网络指标也接入同一个 Prometheus这样压测时一眼就能判断瓶颈到底在客户端、网络还是服务端。我自己最常用的一招是把 JMeter 的 TPS 曲线和被测服务器的 CPU 使用率曲线叠在同一个 Panel 里一重合就能快速看出服务的容量拐点。6.3 持续集成与告警自动化如果你们团队已经有 CI/CD 体系压测监控完全可以做成自动化Jenkins/GitLab CI 里触发 JMeter 非 GUI 压测压测过程中 Prometheus 持续采集同时通过 Alertmanager 配置告警规则比如“响应时间超过 500ms 持续 3 分钟”或“错误率超过 1% 持续 5 分钟”触发后调用企业微信/钉钉机器人通知。这样夜间无人值守压测时任何异常都能第一时间找到人。告警规则在 Prometheus 里配置也很简单groups: - name: jmeter_alerts rules: - alert: JMeterErrorRateHigh expr: sum(rate(jmeter_test_errors_count[5m])) / sum(rate(jmeter_test_requests_count[5m])) 0.01 for: 3m labels: severity: warning annotations: summary: 压测错误率超过 1%这套东西本质上是用开源组件搭了一个轻量级可观测平台不只是压测能用服务监控、接口监控甚至业务指标监控都能复用同一套基础设施。我后来在团队里落地时就是把 Prometheus 配置、Grafana 面板 JSON 以及 JMeter 测试计划模板放到 Git 仓库统一管理新项目直接复制模板改参数从准备环境到看到第一个监控曲线通常一支烟的时间就够了。最后再分享一个我在实际使用中的小技巧把压测脚本、面板 JSON 和 prometheus.yml 全部纳入版本管理并打上标签。每次压测后记录这次压测的基准曲线比如上周的 P95 是多少、TPS 峰值是多少。下次压测时把两次曲线叠在同一个 Grafana Dashboard 里对比就能非常直观地看出代码变更或扩容带来的性能变化。这种前后对比的价值比单纯跑一组数据大得多。这套监控方案最开始可能只是为了“看得见”但真正用熟以后你会发现它能帮你回答很多比“压测过了没”更重要的问题。
返回列表