从 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.yml 或 application.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
正常输出应包含 prometheus 和 grafana 两个容器。此时分别访问以下地址验证服务是否就绪:
- Prometheus:http://localhost:9090 —— 在 Status → Targets 页面中,应该能看到
spring-boot-app的状态为 UP - Grafana:http://localhost:3000 —— 使用用户名
admin、密码admin登录
四、配置 Grafana:连接数据源与导入仪表盘
4.1 添加 Prometheus 数据源
登录 Grafana 后,按以下步骤配置数据源:
- 左侧菜单点击 Connections → Data sources → Add data source
- 搜索并选择 Prometheus
- 在 Connection URL 中输入
http://prometheus:9090(因为 Prometheus 和 Grafana 在同一个 Docker 网络中,容器之间可以通过服务名直接访问) - 点击 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 接口指标等核心面板。
导入步骤:
- 左侧菜单点击 Dashboards → New → Import
- 在 Import via grafana.com 输入框中填入仪表盘 ID:22108
- 点击 Load,在后续页面中选择上一步配置的 Prometheus 数据源
- 点击 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\"}中的method和uri就是标签。标签用于多维筛选和分析,但标签值应当是有限的枚举类型(如 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 部署和通知渠道配置。
八、生产环境避坑指南
- Actuator 端点安全加固:生产环境务必通过
management.endpoints.web.exposure.include限制暴露的端点,只保留health, metrics, prometheus三个核心端点,并配合 Spring Security 启用 Basic Auth 或 OAuth2 认证。 - 指标爆炸防范:不要在标签中使用
userId、sessionId、requestId等无限基数的值。这类数据应该通过链路追踪(Tracing)方案来处理。 - Prometheus 数据持久化:本文示例为了简洁未做数据持久化配置,生产环境务必挂载外部存储卷或将时序数据存入远端 TSDB。
- 多实例聚合:部署多个 Spring Boot 实例时,可以在 Prometheus 配置中使用
kubernetes_sd_configs实现服务发现,或通过统一的标签(如application=order-service)区分不同实例,以便 Grafana 查询时按服务名聚合。 - 监控组件资源规划:Prometheus 和 Grafana 容器建议配置 CPU 和内存限制,避免监控组件自身消耗过多资源影响业务应用。
系列拓展阅读
本文属于 MACS Dev Hub“现代架构与编码解决方案”系列中工程化配套体系的一部分。如果你对 Java 应用的容器化和编排部署感兴趣,推荐继续阅读:
- GitHub Actions 构建 Java 项目并推送 Docker 镜像——配置 CI/CD 流水线,将代码提交自动构建为 Docker 镜像
- VS Code Remote + JetBrains Gateway:远程开发哪家强?——配置远程开发环境,让大规模 Java 项目编译不再卡顿
本系列后续还将深入探讨 Spring Boot 3.4 Docker 镜像最佳实践(含分层构建)和 Java 应用接入 OpenTelemetry 全链路追踪,敬请期待。
本文为 MACS Dev Hub 原创,如需转载请联系授权。









