Modern Architecture
& Coding Solutions

Java 应用接入 Prometheus + Grafana 全记录

从 Micrometer 埋点到可视化大盘,构建企业级 Java 监控体系

引言:你的 Spring Boot 应用“裸奔”多久了?

半夜三点,你被一通紧急电话吵醒:“线上服务卡死了,用户都在投诉!”你睡眼惺忪地打开电脑,查日志、翻监控、看 CPU 占用……半小时过去了,你才定位到问题——某个接口的数据库连接池耗尽。而这半小时里,用户可能已经流失了几百个。

这并非虚构的场景。让应用“裸奔”上线,是很多团队正在悄悄做的最危险的事。 没有监控体系的应用,就像没有仪表盘的汽车——你永远不知道油还有多少、水温是不是已经爆表。等故障真正发生时,你已经错过了最佳的干预窗口。

传统的日志排查方式在海量日志和分布式调用的复杂环境下,已远远跟不上节奏。我们需要一套实时、可视化、可告警的监控体系,而这正是 Prometheus + Grafana 这套黄金组合可以做到的事情。

本文将从头搭建一套完整的 Java 应用监控体系:基于 Spring Boot 3.x + Micrometer 暴露 Prometheus 格式的指标数据,通过 Docker Compose 一键部署 Prometheus 和 Grafana,配置数据源并导入可视化面板,最后补充自定义业务指标和告警规则。文章会沿用本系列之前配置的 《WSL2 + Docker Desktop:Windows 下的完美 Java 开发环境》 环境,在此基础上用 Docker 快速部署监控组件。

一、技术栈概览:架构的三个核心组件

在动手之前,先花一分钟理清这三个组件各自扮演什么角色,以及它们之间是怎么配合的。

Prometheus:时序数据库 + 指标采集器

Prometheus 是由 SoundCloud 开源的一套时序数据库监控系统,天生为云原生环境设计。它通过 HTTP 协议主动拉取(Pull)被监控组件的状态,不需要在被监控端部署额外的推送代理,配置也极其灵活。Prometheus 存储的核心是时序数据——带时间戳的键值对,格式为 指标名{标签名=标签值,...} 数值 时间戳,例如 http_requests_total{method=\"GET\", path=\"/api/user\"} 12589 1710000000,表示在某个时间点用户查询接口的请求总数是 12589 次。

Grafana:可视化仪表盘

Grafana 是一款开源的可视化仪表系统,被誉为业界最优秀的仪表可视化工具。它不对数据源作假设,Prometheus、MySQL、InfluxDB 等都可以作为它的数据源。Grafana 通过调用 PromQL(Prometheus 的查询语言)查询 Prometheus 中的时序数据,然后把数据转化成各种直观的图表(折线图、柱状图、仪表盘、热力图等)展示在仪表盘上。你可以这样理解:Grafana 是仪表盘,Prometheus 是藏在仪表盘后面的数据源。

Micrometer + Actuator:数据采集端

Spring Boot Actuator 是 Spring 生态的监控组件,负责暴露应用的健康状态和运行指标。而 Micrometer 是一个类似 SLF4J 的度量门面(Facade),为 Java 平台上的性能数据收集提供了统一的 API 接口,支持 Timer、Gauge、Counter 等多种指标类型,同时可以接入 Prometheus、InfluxDB、Datadog 等不同的监控系统。在 Spring Boot 中,Actuator 与 Micrometer 打通,你的应用只需引入 Micrometer 的 Prometheus Registry,就能在 /actuator/prometheus 端点自动暴露应用内各种标准指标(JVM 内存、线程池、GC 频率、接口 QPS 等)。

这套组合的工作流程可以概括为:Spring Boot 应用通过 Micrometer 埋点 → Actuator 将指标暴露为 Prometheus 格式 → Prometheus 定期拉取并存储 → Grafana 通过 PromQL 查询并可视化。三者各司其职,共同构成完整的监控闭环。

二、Spring Boot 项目集成:三步完成埋点

2.1 添加核心依赖

在 Spring Boot 3.x 项目的 pom.xml 中添加以下两个依赖:

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

<!-- Micrometer Prometheus Registry -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

2.2 配置 Actuator 端点暴露

application.ymlapplication.properties 中配置 Actuator,启用 Prometheus 端点:

management:
  endpoints:
    web:
      exposure:
        include: "*"          # 生产环境建议只暴露 health, prometheus, metrics
  endpoint:
    health:
      show-details: always   # 显示健康检查详情
    metrics:
      enabled: true
    prometheus:
      enabled: true           # 启用 Prometheus 专用端点

⚠️ 生产环境安全提示include: "*" 会暴露所有 Actuator 端点(包括 env、configprops、heapdump 等敏感信息),生产环境务必只暴露必需的端点,例如 include: "health, prometheus, metrics",并配置 Spring Security 为端点增加 Basic Auth 认证。

2.3 验证端点可用

启动 Spring Boot 应用后,访问 http://localhost:8080/actuator/prometheus,应该能看到大量以 # HELP# TYPE 开头的指标数据。如果能看到类似下面的内容,说明配置成功了:

# HELP jvm_memory_used_bytes Used bytes of a given JVM memory area
# TYPE jvm_memory_used_bytes gauge
jvm_memory_used_bytes{area="heap", id="PS_Eden_Space",} 1.024e+08
jvm_memory_used_bytes{area="heap", id="PS_Old_Gen",} 2.56e+08
# HELP http_server_requests_seconds Duration of HTTP server requests
# TYPE http_server_requests_seconds summary
http_server_requests_seconds_count{method="GET", outcome="SUCCESS", status="200", uri="/actuator/prometheus",} 5.0

三、监控组件部署:用 Docker Compose 一键拉起

本文沿用 WSL2 + Docker Desktop 环境,使用 Docker Compose 部署 Prometheus 和 Grafana。在项目根目录下创建 monitoring/ 目录,新建以下配置文件。

3.1 Prometheus 抓取配置

创建 monitoring/prometheus/prometheus.yml,配置抓取 Spring Boot 应用的指标:

global:
  scrape_interval: 15s   # 抓取间隔
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'spring-boot-app'
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets: ['host.docker.internal:8080']   # Windows 下访问宿主机 Spring Boot

💡 跨网络说明:Windows + WSL2 + Docker 环境有一个特殊之处:容器内部无法直接使用 localhost:8080 访问宿主机上运行的 Spring Boot 应用。解决方式是在 Docker Compose 中使用 extra_hosts 配置,或者在 Prometheus 配置中将目标地址设为 host.docker.internal:8080——这是 Docker Desktop 为宿主机提供的专用 DNS 名称。

3.2 Docker Compose 完整配置

创建 monitoring/docker-compose.yml

version: '3.8'

services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
    extra_hosts:
      - "host.docker.internal:host-gateway"   # 让容器能访问宿主机
    restart: unless-stopped

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin   # 初始密码,首次登录后建议修改
    volumes:
      - grafana-storage:/var/lib/grafana
    depends_on:
      - prometheus
    restart: unless-stopped

volumes:
  grafana-storage:

3.3 启动监控组件

monitoring/ 目录下执行以下命令启动容器:

docker-compose up -d

等待几十秒容器启动完成后,确认两个服务都已正常运行:

docker ps

正常输出应包含 prometheusgrafana 两个容器。此时分别访问以下地址验证服务是否就绪:

  • Prometheus:http://localhost:9090 —— 在 Status → Targets 页面中,应该能看到 spring-boot-app 的状态为 UP
  • Grafana:http://localhost:3000 —— 使用用户名 admin、密码 admin 登录

四、配置 Grafana:连接数据源与导入仪表盘

4.1 添加 Prometheus 数据源

登录 Grafana 后,按以下步骤配置数据源:

  1. 左侧菜单点击 ConnectionsData sourcesAdd data source
  2. 搜索并选择 Prometheus
  3. Connection URL 中输入 http://prometheus:9090(因为 Prometheus 和 Grafana 在同一个 Docker 网络中,容器之间可以通过服务名直接访问)
  4. 点击 Save & test,如果提示 Data source is working,说明连接成功

4.2 导入官方推荐仪表盘

Grafana Labs 维护了一个官方仪表盘库,其中 JVM Spring Boot 3 dashboard (ID: 22108) 是最适合 Spring Boot 3.x 应用的选项,专为通过 Prometheus 监控 Java 应用而设计,涵盖了 JVM 内存、GC 分析、线程状态和 HTTP 接口指标等核心面板。

导入步骤:

  1. 左侧菜单点击 DashboardsNewImport
  2. Import via grafana.com 输入框中填入仪表盘 ID:22108
  3. 点击 Load,在后续页面中选择上一步配置的 Prometheus 数据源
  4. 点击 Import

几秒钟后,仪表盘就会自动加载并开始展示你应用的指标数据。导入完成后,在 Dashboards → Browse 中可以看到新导入的仪表盘。

五、核心指标解读:看懂仪表盘上的数据

Dashboard 导入成功后,仪表盘上会展示几十个指标面板。下面重点讲解 Java 开发者需要关注的几类核心指标:

5.1 JVM 内存指标

JVM 内存是 Java 应用最常见的故障根源之一。重点关注以下面板:

  • Heap Memory Used:堆内存已用量,如果持续逼近最大值(-Xmx 设置的上限),说明存在内存泄露或缓存配置不合理
  • Non-Heap Memory Used:元空间(Metaspace)和代码缓存区已用量,通常随类加载而增长,异常增长可能意味着动态类生成失控
  • GC Pause Duration:垃圾回收停顿时间总和,单次停顿超过 200ms 就需要排查原因

5.2 线程与 GC 指标

  • Active Threads:当前活跃线程数,监控长期趋势可以发现线程泄露
  • GC Cycles:GC 总次数,新生代(PS Scavenge)频繁过高说明对象创建过多;老年代(PS MarkSweep)频繁出现则说明内存不足或内存泄露
  • GC Time:GC 总耗时,JVM 推荐目标是将 GC 总开销控制在应用总 CPU 时间的 1% 以内

5.3 HTTP 请求性能指标

  • Request Rate:应用 QPS,与业务流量相关;突降可能代表服务不可达,突升则要确认是否遭遇攻击或热点事件
  • Request Duration (P50/P95/P99):百分位延迟,P99 更能反映真实用户体验,用于设置 SLA 告警阈值
  • Error Rate:HTTP 请求错误比例,通常按照 4xx(客户端错误)和 5xx(服务端错误)分类统计

六、自定义业务指标:用代码埋点

标准 Dashboard 能满足 JVM 和 HTTP 监控需求,但业务场景下的专属指标同样重要。比如电商系统需要监控“订单创建成功率”,支付系统需要监控“支付超时次数”。Micrometer 提供了多种指标类型供开发者灵活埋点。

6.1 Counter:统计订单创建次数

Counter 是一个单调递增的计数器,适用于统计请求总数、错误次数等指标:

@Service
public class OrderService {
    private final Counter orderCounter;

    public OrderService(MeterRegistry registry) {
        // 注册一个 Counter 指标
        this.orderCounter = Counter.builder("order.created.total")
                .description("Total number of orders created")
                .register(registry);
    }

    public void createOrder(OrderDto dto) {
        // 业务逻辑...
        orderCounter.increment();  // 每次创建成功,计数 +1
    }
}

6.2 Timer:监控核心接口延迟

Timer 专门用于统计方法的耗时分布,会自动生成调用次数、总耗时以及延迟分桶数据:

@Service
public class PaymentService {
    private final Timer paymentTimer;

    public PaymentService(MeterRegistry registry) {
        this.paymentTimer = Timer.builder("payment.process.duration")
                .description("Time taken to process payment")
                .publishPercentiles(0.5, 0.95, 0.99)  // 预计算分位数
                .register(registry);
    }

    public void processPayment(PaymentRequest request) {
        // Timer 配合 Recordable 接口自动记录耗时
        paymentTimer.record(() -> {
            // 实际的支付处理逻辑...
        });
    }
}

6.3 Gauge:监控队列积压长度

Gauge 用于观察可增可减的瞬时状态值,比如线程池大小、缓存命中率、队列积压长度等:

@Component
public class TaskQueueMonitor {
    private final BlockingQueue<Task> taskQueue = new LinkedBlockingQueue<>(1000);

    public TaskQueueMonitor(MeterRegistry registry) {
        // Gauge 必须绑定一个函数式引用(不传新值,每次由 Prometheus 抓取时回调获取最新值)
        registry.gauge("task.queue.size", taskQueue, BlockingQueue::size);
    }

    public void addTask(Task task) {
        taskQueue.offer(task);
    }
}

⚠️ 指标设计最佳实践:埋点时要注意标签(Tag)的使用规范。标签是 Prometheus 指标的重要组成部分,例如 http_server_requests_seconds_count{method=\"GET\", uri=\"/api/order\"} 中的 methoduri 就是标签。标签用于多维筛选和分析,但标签值应当是有限的枚举类型(如 HTTP 方法、状态码、地区编码等),不要将 sessionId、userId、message 等无限增长的值作为标签,否则会造成指标爆炸、存储膨胀、查询性能下降。

6.4 在 Grafana 中查询自定义指标

添加自定义埋点后,你的应用会在 /actuator/prometheus 端点额外暴露这些业务指标。在 Grafana Dashboards 中新建一个面板(Add Panel),在 PromQL 查询框中输入:

# 查询过去 5 分钟内订单创建速率的增长
rate(order_created_total[5m])

# 查询支付处理耗时的 P99
histogram_quantile(0.99, sum(rate(payment_process_duration_bucket[5m])) by (le))

# 查询当前任务队列积压长度
task_queue_size

七、告警配置:用 Alert 实现自动通知

监控的最终目的是在问题发生前或发生的第一时间自动通知到人。Prometheus 通过 Alertmanager 组件来管理告警规则和通知渠道。

7.1 核心告警规则示例

创建 monitoring/prometheus/alerts.yml

groups:
  - name: spring-boot-alerts
    rules:
      # 实例下线告警
      - alert: InstanceDown
        expr: up{job="spring-boot-app"} == 0
        for: 1m
        annotations:
          summary: "Spring Boot 实例 {{ $labels.instance }} 已下线"

      # JVM 堆内存使用过高告警(超过 85%)
      - alert: HighHeapUsage
        expr: (sum(jvm_memory_used_bytes{area="heap"}) / sum(jvm_memory_max_bytes{area="heap"})) > 0.85
        for: 5m
        annotations:
          summary: "JVM 堆内存使用率超过 85%"

将告警规则文件挂载到 Prometheus 配置中,并在 prometheus.yml 中添加引用:

rule_files:
  - "alerts.yml"

7.2 对接 Alertmanager(可选)

完整的告警链路还需要部署 Alertmanager 组件并配置 webhook 通知渠道(企业微信、钉钉、邮件等)。本文限于篇幅不展开,读者可以参阅 Prometheus 官方文档完成 Alertmanager 部署和通知渠道配置。

八、生产环境避坑指南

  1. Actuator 端点安全加固:生产环境务必通过 management.endpoints.web.exposure.include 限制暴露的端点,只保留 health, metrics, prometheus 三个核心端点,并配合 Spring Security 启用 Basic Auth 或 OAuth2 认证。
  2. 指标爆炸防范:不要在标签中使用 userIdsessionIdrequestId 等无限基数的值。这类数据应该通过链路追踪(Tracing)方案来处理。
  3. Prometheus 数据持久化:本文示例为了简洁未做数据持久化配置,生产环境务必挂载外部存储卷或将时序数据存入远端 TSDB。
  4. 多实例聚合:部署多个 Spring Boot 实例时,可以在 Prometheus 配置中使用 kubernetes_sd_configs 实现服务发现,或通过统一的标签(如 application=order-service)区分不同实例,以便 Grafana 查询时按服务名聚合。
  5. 监控组件资源规划:Prometheus 和 Grafana 容器建议配置 CPU 和内存限制,避免监控组件自身消耗过多资源影响业务应用。

系列拓展阅读

本文属于 MACS Dev Hub“现代架构与编码解决方案”系列中工程化配套体系的一部分。如果你对 Java 应用的容器化和编排部署感兴趣,推荐继续阅读:

本系列后续还将深入探讨 Spring Boot 3.4 Docker 镜像最佳实践(含分层构建)和 Java 应用接入 OpenTelemetry 全链路追踪,敬请期待。

本文为 MACS Dev Hub 原创,如需转载请联系授权。

赞(0) 打赏
未经允许不得转载:MACS Dev Hub » Java 应用接入 Prometheus + Grafana 全记录

觉得文章有用就打赏一下文章作者

非常感谢你的打赏,我们将继续提供更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫

微信扫一扫

登录

找回密码

注册