基于Grafana+Prometheus+Micrometer的JVM性能监控实战指南
1. 为什么需要JVM性能监控系统?
第一次线上服务崩溃的经历让我记忆犹新。那天凌晨三点,报警电话把我从睡梦中惊醒,线上订单服务完全瘫痪。排查了半天才发现是JVM老年代内存泄漏导致Full GC频繁触发,最终拖垮了整个系统。如果当时有一套完善的JVM监控系统,就能提前发现内存异常增长的趋势,避免这次事故。
这就是为什么我们需要搭建Grafana+Prometheus+Micrometer这套黄金组合。它们分别扮演着:
- Micrometer:应用层的指标采集器(相当于汽车的传感器)
- Prometheus:时序数据库和告警中枢(相当于行车电脑)
- Grafana:数据可视化平台(相当于仪表盘)
实测下来,这套方案有三个突出优势:
- 全链路覆盖:从JVM内部指标(堆内存、线程数)到系统资源(CPU、磁盘)都能监控
- 实时性强:默认15秒采集一次数据,能捕捉到突发性性能波动
- 零侵入性:对业务代码几乎没有影响,加个依赖改个配置就能用
我经手过的电商、金融项目中,90%的JVM问题(内存泄漏、线程阻塞、GC异常)都能通过这个方案提前预警。下面我会手把手带你搭建这套系统,包含我踩过的所有坑和优化技巧。
2. Spring Boot应用监控配置
2.1 Actuator基础配置
Spring Boot自带的Actuator模块是监控系统的起点。最近在给一家物流公司做监控升级时,发现他们还在用1.x版本的配置方式,导致很多关键指标缺失。这里分享正确的新版配置:
<!-- pom.xml必须包含这两个依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency>关键的application.yml配置(这些参数都是我压测后优化的值):
management: endpoints: web: exposure: include: "*" # 暴露所有端点 base-path: /monitor # 自定义路径更安全 endpoint: health: show-details: always prometheus: enabled: true metrics: tags: application: ${spring.application.name} # 重要!用于区分不同服务 export: prometheus: step: 15s # 采集间隔配置完成后访问http://localhost:8080/monitor/prometheus,你会看到类似这样的输出:
jvm_memory_used_bytes{area="heap",id="PS Survivor Space"} 1.5672328E7 jvm_threads_live_threads 42 http_server_requests_seconds_count{method="GET",uri="/api/orders",status="200"} 153避坑指南:
- 不要直接用
/actuator作为路径,容易被扫描工具攻击 - 生产环境建议通过
include精细控制暴露的端点(如health,info,prometheus) - 如果看到
404,检查是否漏了micrometer-registry-prometheus依赖
2.2 Micrometer高级技巧
Micrometer的强大之处在于它能自动收集数十种JVM指标,但有些关键指标需要特别关注:
GC相关指标(直接影响系统卡顿)
jvm_gc_pause_seconds_count{gc="G1 Young Generation"} jvm_gc_pause_seconds_sum{gc="G1 Old Generation"}线程状态监控(死锁预警)
jvm_threads_states_threads{state="BLOCKED"}HTTP接口性能(定位慢请求)
http_server_requests_seconds_max{uri="/api/payment"}
我常用的自定义指标配置示例:
@Bean MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() { return registry -> registry.config() .commonTags("region", System.getenv("AWS_REGION")) // 区分部署区域 .commonTags("instance", hostname); // 标识实例 } // 自定义业务指标 Counter orderCounter = Metrics.counter("order.count", "type", "vip"); orderCounter.increment();3. Prometheus数据采集实战
3.1 安装与基础配置
Prometheus的安装其实很简单,但配置中有很多经验性的参数需要调整。这是我优化过的prometheus.yml配置:
global: scrape_interval: 15s # 抓取频率 evaluation_interval: 15s # 规则评估频率 scrape_configs: - job_name: 'java-apps' metrics_path: '/monitor/prometheus' scrape_interval: 10s # JVM监控需要更高频率 static_configs: - targets: ['app1:8080', 'app2:8080'] labels: env: 'prod' tier: 'backend' - job_name: 'node' static_configs: - targets: ['192.168.1.100:9100']启动命令建议用nohup(生产环境建议用systemd):
nohup ./prometheus \ --config.file=prometheus.yml \ --web.listen-address=0.0.0.0:9090 \ --storage.tsdb.retention.time=30d \ > prometheus.log 2>&1 &关键参数说明:
storage.tsdb.retention.time:数据保留时间(默认15天)--web.enable-lifecycle:支持热重载配置(发POST到/-/reload)scrape_timeout:建议设置为scrape_interval的2/3
3.2 告警规则配置
在prometheus.yml同目录下创建alert.rules.yml:
groups: - name: jvm-alerts rules: - alert: HighHeapUsage expr: sum(jvm_memory_used_bytes{area="heap"}) by (instance) / sum(jvm_memory_max_bytes{area="heap"}) by (instance) > 0.85 for: 5m labels: severity: warning annotations: summary: "High heap usage on {{ $labels.instance }}" description: "Heap usage is {{ $value }}%" - alert: GCTooFrequent expr: increase(jvm_gc_pause_seconds_count[1m]) > 10 for: 10m labels: severity: critical加载规则文件需要在prometheus.yml中添加:
rule_files: - 'alert.rules.yml'实用告警规则:
- 线程数突增:
jvm_threads_live_threads > 500 - HTTP错误率:
sum(rate(http_server_requests_seconds_count{status=~"5.."}[1m])) by (uri) / sum(rate(http_server_requests_seconds_count[1m])) by (uri) > 0.01 - 系统负载:
node_load5 / count(count(node_cpu_seconds_total{mode="system"}) by (cpu)) > 2
4. Grafana可视化搭建
4.1 安装与数据源配置
用Docker安装Grafana是最佳实践:
docker run -d \ -p 3000:3000 \ --name=grafana \ -v /data/grafana:/var/lib/grafana \ grafana/grafana:9.0.0配置Prometheus数据源时要注意:
- URL填写
http://prometheus:9090(如果是容器需要配置网络) - 开启"Scrape interval"覆盖,设置为15s
- 添加Custom HTTP Header进行鉴权(如
Authorization: Bearer xxx)
4.2 仪表盘配置技巧
直接导入现成模板固然方便,但定制化才能发挥最大价值。分享我的JVM监控面板配置要点:
核心图表配置:
内存池使用率
sum(jvm_memory_used_bytes{area=~"heap|nonheap"}) by (area) / sum(jvm_memory_max_bytes{area=~"heap|nonheap"}) by (area)- 显示为Time series
- Y轴格式设为0-100%
- 添加阈值线(85%警告,95%危险)
GC暂停时间热力图
histogram_quantile(0.95, sum(rate(jvm_gc_pause_seconds_bucket[1m])) by (le, gc))- 显示为Heatmap
- 按GC类型分桶
线程状态堆叠图
sum(jvm_threads_states_threads) by (state)- 显示为Stacked bar
- 重点关注BLOCKED状态
布局优化技巧:
- 将关键指标放在顶部(用Stat图表)
- 使用Row分割不同维度的监控
- 添加Annotation标记部署事件
- 设置Variables实现服务切换(如
${app}变量)
5. 生产环境优化方案
5.1 性能调优参数
在高负载场景下(实测QPS>5000),需要调整这些参数:
Prometheus调优:
global: scrape_interval: 30s # 降低采集频率 storage: tsdb: wal_compression: true # 启用WAL压缩 max_block_chunk_segment_size: 512MBGrafana优化:
- 开启
rendering_server使用外部渲染服务 - 配置
[dashboards] min_refresh_interval = 30s - 使用
GF_DATABASE_MAX_IDLE_CONN=10减少数据库连接
- 开启
5.2 高可用方案
对于关键业务系统,建议部署多实例:
Prometheus联邦集群:
scrape_configs: - job_name: 'federate' scrape_interval: 1m honor_labels: true metrics_path: '/federate' params: 'match[]': - '{job="java-apps"}' static_configs: - targets: - 'prometheus-01:9090' - 'prometheus-02:9090'Grafana多数据源:
- 配置多个Prometheus实例为不同数据源
- 使用
--config参数指定不同环境的配置
5.3 安全防护措施
基础安全:
- 为Prometheus和Grafana启用HTTPS
- 配置
basic_auth或OAuth2.0认证 - 限制
/monitor端点的IP访问
敏感数据过滤:
MeterFilter denyTags(String... tagKeys) { return MeterFilter.deny(id -> { for (String tagKey : tagKeys) { if (id.getTag(tagKey) != null) { return true; } } return false; }); }
这套方案在多个千万级用户的产品中验证过稳定性。最近帮一个短视频平台优化后,他们的GC问题排查时间从平均4小时缩短到15分钟。监控系统就像开发者的眼睛,越早搭建收益越大。
