CSDN 可选标题(3组风格)

正文:一篇吃透 Docker+Prometheus 监控Java服务JVM(全实战代码)

一、前言 📢

微服务时代Java应用频繁出现OOM、GC卡顿、线程泄露、堆内存溢出等线上问题,JVM监控是定位性能故障的核心抓手。
Prometheus 搭配 Grafana 是当前云原生最主流的时序监控方案,本文全程基于 Docker / Docker Compose 容器化部署,覆盖:

  1. SpringBoot 接入Micrometer暴露JVM指标
  2. Docker打包Java应用,容器网络互通配置
  3. Prometheus容器抓取JVM指标完整yml配置
  4. Grafana可视化大盘导入+常用JVM PromQL
  5. JVM内存/GC告警规则编写
  6. 完整Mermaid架构流程图、可直接复制的源码配置

整体架构流程图(Mermaid)

可视化告警层

监控采集层

Java服务层

暴露/actuator/prometheus JVM指标

SpringBoot Java容器

Prometheus

JVM堆内存指标

GC停顿/GC次数指标

活跃线程/阻塞线程

接口QPS、耗时

存储时序指标数据

告警规则引擎Alert

Grafana可视化面板

告警通知(钉钉/邮件)

故障排查、性能优化

流程简述:Java应用内置Micrometer暴露标准化Prometheus指标 → Prometheus定时拉取采集存储 → Grafana可视化JVM大盘 → 内存过高/频繁GC自动触发告警。

二、两种Java监控方案对比 🧐

方案1:SpringBoot Micrometer(推荐,本文重点)

适用:SpringBoot 2.x/3.x 微服务,零额外agent,原生集成,开箱自动导出完整JVM指标(堆、非堆、GC、线程、类加载、CPU)

方案2:JMX Exporter JavaAgent

适用:老旧非SpringBoot Java项目(Tomcat、普通Java Jar),通过javaagent挂载采集JMX数据

本文优先讲解Micrometer方案,文末补充JMX Exporter容器适配方式。

三、步骤1:SpringBoot项目集成Prometheus暴露JVM指标 📡

3.1 Maven pom.xml 引入依赖

在父 pom.xml 的 中声明的依赖

<!-- SpringBoot监控端点核心 -->

            <!-- =================================================== -->
            <!-- SpringBoot监控端点核心 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
                <version>${spring-boot.version}</version>
            </dependency>
            <!-- Micrometer Prometheus注册表,自动生成JVM指标 -->
            <dependency>
                <groupId>io.micrometer</groupId>
                <artifactId>micrometer-registry-prometheus</artifactId>
                <version>1.14.2</version>
            </dependency>
            <!-- =================================================== -->

在子模块 pom.xml 中应用

        <!-- SpringBoot Actuator监控端点 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <!-- Micrometer Prometheus监控指标 -->
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-registry-prometheus</artifactId>
        </dependency>

再在项目的拦截器放行路径,不校验登录

.........
         // Prometheus监控指标端点,允许监控系统匿名访问
         // 用于Prometheus Server定期拉取应用的监控指标数据,无需登录认证
         .requestMatchers("/actuator/**").permitAll()

3.2 application.yml 监控配置(完整可复制)

spring:
  application:
    name: java-jvm-demo # 应用唯一标识,区分多服务监控指标

# Actuator监控端点配置
management:
  endpoints:
    web:
      exposure:
        # 开放健康检查、prometheus指标端点
        include: health,prometheus,info,metrics
  metrics:
    export:
      prometheus:
        enabled: true
    tags:
      # 全局指标标签,多实例、多环境区分
      env: dev
    distribution:
      percentiles-histogram:
        http.server.requests: true # 开启接口响应分位数统计(95/99线)
  endpoint:
    health:
      show-details: always # 展示完整健康详情

配置完成后,启动项目访问地址:http://127.0.0.1:8080/actuator/prometheus,页面会输出海量JVM原生指标,核心指标示例:

  • jvm_memory_used_bytes:堆/非堆内存占用
  • jvm_gc_pause_seconds:GC停顿耗时
  • jvm_threads_live:当前存活线程数
  • jvm_classes_loaded_classes:加载类数量

在这里插入图片描述

3.3 自定义业务指标(扩展实战代码)

除原生JVM指标,可埋点业务计数器,监控接口调用量:

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;

@RestController
public class JvmDemoController {
    // 注入指标注册器
    @Resource
    private MeterRegistry meterRegistry;
    private final Counter apiVisitCounter;

    // 初始化业务计数器
    public JvmDemoController(MeterRegistry registry) {
        this.apiVisitCounter = registry.counter("demo_api_visit_count", "api", "/hello");
    }

    @GetMapping("/hello")
    public String hello() {
        apiVisitCounter.increment(); // 每次访问计数器+1
        return "JVM监控Demo服务运行正常";
    }
}

3.4 Java应用Dockerfile打包(容器化部署)

# 基础JDK镜像
FROM openjdk:17-jdk-slim
WORKDIR /app
# 复制打包后的jar包
COPY target/jvm-monitor-demo-0.0.1-SNAPSHOT.jar app.jar
# JVM启动参数,优化监控日志
ENTRYPOINT ["java","-jar","app.jar"]
# 暴露服务端口
EXPOSE 8080

构建镜像命令:

docker build -t java-jvm-demo:1.0 .
# 启动Java容器,映射8080端口
docker run -d --name java-app -p 8080:8080 java-jvm-demo:1.0

四、步骤2:Docker Compose 部署Prometheus+Grafana监控栈 🐳

4.1 目录结构

monitor/
├── docker-compose.yml       # 编排文件
├── prometheus/
│   └── prometheus.yml       # Prometheus抓取配置(核心)
└── grafana-data/            # Grafana持久化数据(自动生成)

4.2 prometheus/prometheus.yml 配置(关键!抓取Java容器JVM指标)

重点:Docker容器互通,Linux宿主机网关172.17.0.1;Windows/Mac Docker Desktop使用host.docker.internal

global:
  scrape_interval: 10s # 每10秒采集一次指标
  evaluation_interval: 10s # 告警规则检测间隔

# JVM监控抓取任务
scrape_configs:
  - job_name: "jobName-java-jvm-monitor"
    metrics_path: "/actuator/prometheus"
    static_configs:
      # 同一个docker网络就写服务名称,不同compose就写内网ip
      - targets: ["zgb-admin:7777"]
        labels:
          service: labelsService-java-jvm-monitor

4.3 docker-compose.yml 完整编排文件

新的一个独立的配置
version: '3.8'
volumes:
  prom_data: # Prometheus时序数据持久化
  grafana_data: # Grafana面板配置持久化

services:
  # Prometheus服务
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
      - prom_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.retention.time=15d' # 数据保存15天
    restart: unless-stopped

  # Grafana可视化面板
  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    ports:
      - "4000:3000"
    volumes:
      - grafana_data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=123456
    depends_on:
      - prometheus
    restart: unless-stopped
如果已经有docker-compose 就加入配置

version: '3.8'

services:
  # ======================== MySQL 数据库 ========================
#  mysql:
#    image: mysql:8.0
#    container_name: zgb-mysql
#    restart: always
#    environment:
#      MYSQL_ROOT_PASSWORD: zgb@2026        # root 密码,部署时请修改
#      MYSQL_DATABASE: zgb_sr               # 自动创建的数据库
#      TZ: Asia/Shanghai
#    ports:
#      - "3306:3306"
#    volumes:
#      - mysql-data:/var/lib/mysql          # 数据持久化
#      - ./sql:/docker-entrypoint-initdb.d  # 首次启动自动执行 sql 目录下的初始化脚本
#    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
#    networks:
#      - zgb-net

  # ======================== Redis 缓存 ========================
#  redis:
#    image: redis:7-alpine
#    container_name: zgb-redis
#    restart: always
#    ports:
#      - "6379:6379"
#    command: redis-server --requirepass zgb@2026  # Redis 密码,部署时请修改
#    volumes:
#      - redis-data:/data
#    networks:
#      - zgb-net

  # ======================== ZGB 应用服务 ========================
  zgb-admin:
    image: crpi-2toxc20jd1dwczcw.cn-shenzhen.personal.cr.aliyuncs.com/zhuguanbo/zgb-admin:1.0.0
    container_name: zgb-admin
    restart: always
    ports:
      - "7777:7777"                        # Spring Boot HTTP 端口
      - "9999:9999"                        # Netty GPS 数据接收端口
    environment:
      TZ: Asia/Shanghai
      JAVA_OPTS: "-Xms512m -Xmx512m -Djava.security.egd=file:/dev/./urandom"
      # 激活生产环境配置
      SPRING_PROFILES_ACTIVE: dev
    volumes:
      - app-logs:/app/logs               # 日志持久化
      - app-upload:/app/uploadPath        # 上传文件持久化
    networks:
      - zgb-net

  # ======================== Prometheus监控 ========================

  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
      - prom_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.retention.time=15d'
    restart: unless-stopped
    networks:
      - zgb-net


  # ======================== Grafana可视化面板 ========================
  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    ports:
      - "4000:3000"
    volumes:
      - grafana_data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=123456
    depends_on:
      - prometheus
    restart: unless-stopped
    networks:
      - zgb-net

volumes:
  # 原有业务持久卷
  mysql-data:
  redis-data:
  app-logs:
  app-upload:
  # 新增监控持久卷
  prom_data: # Prometheus时序数据持久化
  grafana_data: # Grafana面板配置持久化

networks:
  zgb-net:
    driver: bridge



4.4 一键启动监控栈

# 进入monitor目录
cd monitor
# 后台启动所有容器
docker-compose up -d
# 查看容器运行状态
docker-compose ps

访问地址:

  • Prometheus控制台:http://localhost:9090 → Status → Targets 查看Java服务是否UP
  • Grafana面板:http://localhost:4000 账号admin/123456

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

五、步骤3:Grafana配置JVM可视化大盘 📊

  1. Grafana添加数据源:Configuration → Data sources → Add data source 选择Prometheus,地址填写http://prometheus:9090(容器互通域名),保存测试连通。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  2. 导入JVM标准大盘:Grafana官方SpringBoot JVM模板ID 4701,直接Import即可自动生成完整监控视图,包含:

    • 堆/非堆内存实时曲线
    • 老年代/新生代GC频率、停顿时间
    • 线程总数、阻塞线程、死锁线程
    • 类加载数量、编译耗时
    • HTTP接口QPS、99分位响应延迟

在这里插入图片描述

如果4701不存在,可以尝试

19004(SpringBoot3 专用,最新)
12900(通用 JVM Micrometer,替代 4701)
11946(极简 JVM 大盘,无依赖)

在这里插入图片描述
在这里插入图片描述

常用JVM核心PromQL查询语句(直接复制到Grafana)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

下次进来在哪里能查看到这样页面?
在这里插入图片描述

  1. 堆内存使用率
(jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"}) * 100
  1. 5分钟GC平均次数
rate(jvm_gc_pause_seconds_count[5m])
  1. 活跃线程总数
jvm_threads_live_threads
  1. 接口99%响应耗时
histogram_quantile(0.99, sum(rate(http_server_requests_seconds_bucket[1m])) by (le,uri))

六、步骤4:JVM高内存/频繁GC告警规则配置 ⚠️

在prometheus.yml同级目录新建alert-rules.yml
在这里插入图片描述

groups:
- name: jvm-alert-rules
  rules:
  # 规则1:堆内存占用超过80%持续5分钟告警
  - alert: JvmHeapMemoryHigh
    expr: (jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"}) > 0.8
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "Java应用堆内存占用过高"
      description: "服务{{$labels.service}}堆内存使用率{{$value | humanizePercentage}},持续超过80%"

  # 规则2:每分钟GC次数超过10次,频繁GC告警
  - alert: JvmGcFrequent
    expr: rate(jvm_gc_pause_seconds_count[1m]) > 10
    for: 2m
    labels:
      severity: critical
    annotations:
      summary: "Java服务GC频繁,存在内存泄露风险"

修改prometheus.yml加载告警文件,在global下新增:

rule_files:
  - "alert-rules.yml"

在这里插入图片描述

重启Prometheus容器生效:docker-compose restart prometheus

七、常见踩坑避坑指南 💡

  1. Prometheus Targets显示DOWN:
    • 检查extra_hosts配置,Linux不能用host.docker.internal,替换172.17.0.1
    • Java容器防火墙未开放8080端口,确认curl可访问/actuator/prometheus
  2. JVM指标缺失:未开启micrometer-registry-prometheus依赖,或端点未暴露prometheus
  3. Grafana无数据:数据源地址写错,不能填localhost:9090,容器内使用prometheus服务名
  4. 内存告警不触发:scrape采集间隔过长,for持续时间未满足

九、总结 ✅

本文完整覆盖容器化Prometheus监控Java JVM全链路:

  1. SpringBoot Micrometer自动导出全套JVM指标,附带自定义业务埋点代码
  2. Docker Compose一键编排Prometheus+Grafana,全量可复制yml配置
  3. Mermaid架构流程图清晰梳理数据流
  4. 标准Grafana大盘导入、生产级JVM告警规则、通用PromQL
  5. 兼容老旧Java项目JMX Exporter方案与线上踩坑解决方案

整套方案零侵入、容器轻量化,直接落地生产环境,快速定位OOM、GC卡顿、线程泄露等JVM性能故障。

更多推荐