Prometheus - 监控微服务:Spring Boot 应用指标暴露与监控

👋 大家好,欢迎来到我的技术博客!
📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。
🎯 本文将围绕Prometheus这个话题展开,希望能为你带来一些启发或实用的参考。
🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获!
文章目录
Prometheus - 监控微服务:Spring Boot 应用指标暴露与监控
在现代微服务架构中,可观测性(Observability)已成为保障系统稳定性和可维护性的核心支柱之一。随着服务数量激增、调用链路复杂化,传统的日志排查方式已难以满足快速定位问题的需求。此时,指标监控(Metrics Monitoring) 作为可观测性的三大支柱之一(另外两个是日志和追踪),扮演着至关重要的角色。
Prometheus 作为 CNCF(Cloud Native Computing Foundation)毕业的开源监控系统,凭借其强大的多维数据模型、灵活的查询语言 PromQL、高效的时序数据库以及活跃的社区生态,已成为云原生时代事实上的监控标准。而 Spring Boot 作为 Java 生态中最流行的微服务框架,天然支持与 Prometheus 的集成。
本文将深入探讨如何在 Spring Boot 应用中暴露应用指标,并通过 Prometheus 实现高效、可扩展的监控体系。我们将从基础概念入手,逐步构建完整的监控链路,涵盖自动指标采集、自定义业务指标、告警配置、可视化展示等关键环节,并辅以大量可运行的 Java 代码示例。
为什么需要监控 Spring Boot 微服务?
在微服务架构下,一个用户请求可能穿越数十个服务,任何一个环节的性能下降或故障都可能导致整个用户体验受损。如果没有有效的监控手段,排查问题将如同“盲人摸象”。
🔍 常见痛点
- 服务不可用却无感知:服务宕机或响应超时,但运维团队未及时收到通知。
- 性能瓶颈难以定位:CPU 或内存使用率飙升,但无法快速判断是哪个接口或哪段代码导致。
- 资源浪费严重:过度配置资源(如线程池、连接池)造成成本上升,或配置不足导致服务雪崩。
- 缺乏业务视角:仅关注基础设施指标(如 CPU、内存),忽略关键业务指标(如订单创建成功率、支付失败率)。
📊 监控的价值
- 实时告警:在问题发生前或初期阶段发出预警,减少 MTTR(平均修复时间)。
- 性能分析:通过历史指标趋势分析,识别性能瓶颈并优化代码。
- 容量规划:基于资源使用趋势预测未来需求,合理扩容或缩容。
- 业务洞察:将技术指标与业务指标结合,为产品决策提供数据支持。
💡 提示:Prometheus 官方文档详细介绍了其架构和设计理念,建议读者在深入实践前阅读 Prometheus 官方文档。
Prometheus 核心概念速览
在动手之前,我们需要理解 Prometheus 的几个核心概念:
📈 时序数据(Time Series)
Prometheus 将所有监控数据存储为时序数据,即按时间戳组织的数值序列。每条时序由 指标名称(Metric Name) 和一组 标签(Labels) 唯一标识。
例如:
http_requests_total{method="POST", status="200", service="order-service"} 150
http_requests_total是指标名称。{method="POST", status="200", service="order-service"}是标签集合,用于多维切片。150是当前时间点的值。
🕵️♂️ 拉取模型(Pull Model)
与传统监控系统(如 Zabbix)的推送模型不同,Prometheus 采用主动拉取(Pull) 方式从目标服务获取指标。这意味着被监控的服务必须暴露一个 HTTP 接口(通常是 /actuator/prometheus),Prometheus 定期访问该接口抓取数据。
这种设计的优势包括:
- 服务无需依赖监控系统客户端库。
- 网络拓扑更清晰,便于防火墙配置。
- 支持服务发现(Service Discovery),动态发现新服务。
🔧 PromQL:强大的查询语言
Prometheus 提供了名为 PromQL(Prometheus Query Language) 的函数式查询语言,支持聚合、过滤、数学运算等操作。例如:
# 查询过去5分钟内每秒HTTP请求数(速率)
rate(http_requests_total[5m])
# 查询内存使用率超过80%的实例
(instance_memory_usage_bytes / instance_memory_total_bytes) > 0.8
📣 Alertmanager:告警管理
当指标满足特定条件时,Prometheus 可触发告警,并将告警发送给 Alertmanager。Alertmanager 负责去重、分组、静默,并通过邮件、Slack、Webhook 等方式通知相关人员。
在 Spring Boot 中暴露 Prometheus 指标
Spring Boot 2.x 起原生支持 Micrometer,这是一个 vendor-neutral 的应用指标门面(类似 SLF4J 之于日志)。Micrometer 提供了统一的 API,可将指标输出到 Prometheus、Datadog、InfluxDB 等多种后端。
🛠️ 步骤一:添加依赖
在 pom.xml 中添加以下依赖:
<dependencies>
<!-- 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>
</dependencies>
⚠️ 注意:Spring Boot 2.3+ 已将 Micrometer 作为默认依赖,但需显式引入
micrometer-registry-prometheus才能启用 Prometheus 支持。
🌐 步骤二:启用 Prometheus 端点
在 application.yml 中配置 Actuator 端点:
management:
endpoints:
web:
exposure:
include: health,info,prometheus # 暴露 prometheus 端点
endpoint:
prometheus:
enabled: true
metrics:
tags:
application: ${spring.application.name} # 为所有指标添加 application 标签
启动应用后,访问 http://localhost:8080/actuator/prometheus,你将看到类似如下的输出:
# HELP jvm_memory_used_bytes The amount of used memory
# TYPE jvm_memory_used_bytes gauge
jvm_memory_used_bytes{application="order-service",area="heap",id="G1 Eden Space",} 1.23456789E8
jvm_memory_used_bytes{application="order-service",area="heap",id="G1 Old Gen",} 2.3456789E8
...
# HELP http_server_requests_seconds Timer of HTTP server requests
# TYPE http_server_requests_seconds summary
http_server_requests_seconds_count{application="order-service",exception="None",method="GET",outcome="SUCCESS",status="200",uri="/api/orders",} 42
http_server_requests_seconds_sum{application="order-service",exception="None",method="GET",outcome="SUCCESS",status="200",uri="/api/orders",} 1.234
这些指标由 Micrometer 自动收集,涵盖 JVM、Tomcat、HTTP 请求等多个维度。
自动收集的指标详解
Micrometer 为 Spring Boot 应用自动收集了大量开箱即用的指标。以下是几类关键指标:
🖥️ JVM 指标
jvm_memory_used_bytes:JVM 内存使用量(堆/非堆)。jvm_gc_pause_seconds:GC 暂停时间。jvm_threads_live:活跃线程数。jvm_classes_loaded:已加载类数量。
这些指标对诊断内存泄漏、GC 问题至关重要。
🌐 Web 指标
http_server_requests_seconds:HTTP 请求处理时间(直方图类型)。_count:请求总数。_sum:请求总耗时。- 可通过
rate(http_server_requests_seconds_count[5m])计算 QPS。
tomcat_sessions_active_current:当前活跃会话数(若使用 Tomcat)。
📦 缓存与数据源指标
cache_gets_total:缓存命中/未命中次数。hikaricp_connections_active:HikariCP 连接池活跃连接数。
📚 更多自动指标列表可参考 Micrometer 官方文档 - Spring Boot Support。
自定义业务指标
自动指标虽好,但往往无法满足特定业务场景的需求。例如,你可能希望监控:
- 每小时成功创建的订单数。
- 支付失败率。
- 用户登录尝试次数。
Micrometer 提供了丰富的 API 来定义自定义指标。
📏 指标类型
Micrometer 支持四种基本指标类型:
| 类型 | 说明 | 适用场景 |
|---|---|---|
| Counter | 单调递增计数器 | 错误次数、请求总数 |
| Gauge | 可增可减的瞬时值 | 当前队列长度、内存使用量 |
| Timer | 记录事件耗时 | 方法执行时间、HTTP 请求延迟 |
| Distribution Summary | 记录事件大小分布 | 响应体大小、消息队列长度 |
✨ 示例:监控订单创建
假设我们有一个订单服务,希望跟踪成功和失败的订单创建次数。
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
private final Counter orderCreatedSuccess;
private final Counter orderCreatedFailure;
public OrderService(MeterRegistry meterRegistry) {
// 创建两个计数器,带标签区分成功/失败
this.orderCreatedSuccess = Counter.builder("orders_created_total")
.description("Total number of successfully created orders")
.tag("status", "success")
.register(meterRegistry);
this.orderCreatedFailure = Counter.builder("orders_created_total")
.description("Total number of failed order creations")
.tag("status", "failure")
.register(meterRegistry);
}
public void createOrder(OrderRequest request) {
try {
// 业务逻辑:保存订单
saveOrder(request);
orderCreatedSuccess.increment(); // 成功,计数+1
} catch (Exception e) {
orderCreatedFailure.increment(); // 失败,计数+1
throw e;
}
}
private void saveOrder(OrderRequest request) {
// 模拟数据库操作
}
}
访问 /actuator/prometheus,你将看到:
# HELP orders_created_total Total number of successfully created orders
# TYPE orders_created_total counter
orders_created_total{application="order-service",status="success",} 5.0
orders_created_total{application="order-service",status="failure",} 2.0
⏱️ 示例:记录方法执行时间
使用 Timer 记录关键方法的执行时间:
import io.micrometer.core.instrument.Timer;
import org.springframework.stereotype.Service;
@Service
public class PaymentService {
private final Timer paymentProcessingTimer;
public PaymentService(MeterRegistry meterRegistry) {
this.paymentProcessingTimer = Timer.builder("payment_processing_duration_seconds")
.description("Time taken to process a payment")
.register(meterRegistry);
}
public PaymentResult processPayment(PaymentRequest request) {
return paymentProcessingTimer.recordCallable(() -> {
// 模拟支付处理
Thread.sleep(200);
return new PaymentResult("SUCCESS");
});
}
}
Prometheus 将自动记录 _count、_sum 以及分位数(如果配置了 histogram)。
📊 示例:动态 Gauge(如队列长度)
Gauge 通常用于反映当前状态。例如,监控一个工作队列的长度:
import io.micrometer.core.instrument.Gauge;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
@Component
public class TaskQueue {
private final BlockingQueue<Task> queue = new LinkedBlockingQueue<>();
public TaskQueue(MeterRegistry meterRegistry) {
// Gauge 会定期调用 supplier 获取当前值
Gauge.builder("task_queue_size", queue, BlockingQueue::size)
.description("Current number of tasks in the queue")
.register(meterRegistry);
}
public void addTask(Task task) {
queue.offer(task);
}
public Task takeTask() throws InterruptedException {
return queue.take();
}
}
💡 最佳实践:避免在 Gauge 的 supplier 中执行耗时操作,因为它会在每次 scrape 时被调用。
配置 Prometheus 抓取 Spring Boot 指标
现在,我们的 Spring Boot 应用已暴露指标,下一步是配置 Prometheus 来抓取它们。
📄 prometheus.yml 配置
创建 prometheus.yml 文件:
global:
scrape_interval: 15s # 默认抓取间隔
scrape_configs:
- job_name: 'spring-boot-apps'
# 使用 DNS SRV 记录或静态配置
static_configs:
- targets: ['host.docker.internal:8080'] # 本地开发时指向宿主机
labels:
group: 'backend'
🐳 Docker 用户注意:在容器中运行 Prometheus 时,
localhost指向容器自身。若 Spring Boot 应用在宿主机上,需使用host.docker.internal(Mac/Windows)或宿主机 IP(Linux)。
🚀 启动 Prometheus
使用 Docker 快速启动 Prometheus:
docker run -d \
--name=prometheus \
-p 9090:9090 \
-v $(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml \
prom/prometheus
访问 http://localhost:9090,进入 Prometheus Web UI。
在 Status > Targets 页面,你应该看到 spring-boot-apps 任务状态为 UP。
🔍 查询指标
在 Prometheus 查询框中输入:
# 查看所有订单创建指标
orders_created_total
# 计算过去5分钟的订单创建速率(每秒)
rate(orders_created_total[5m])
# 计算支付成功率(成功 / (成功 + 失败))
rate(orders_created_total{status="success"}[5m])
/
ignoring(status) group_left
(rate(orders_created_total[5m]))
📌 提示:PromQL 的
ignoring和group_left用于处理标签不匹配的向量匹配,详见 Prometheus 向量匹配文档。
构建完整的监控架构
在生产环境中,单个 Prometheus 实例可能不足以应对大规模微服务集群。我们需要考虑高可用、长期存储、告警等高级特性。
🧩 架构组件
一个典型的 Prometheus 监控栈包含以下组件:
- Prometheus Server:核心组件,负责抓取、存储、查询。
- Alertmanager:处理告警路由和通知。
- Grafana:可视化面板,提供比 Prometheus 更丰富的图表。
- Thanos/Cortex:用于跨集群聚合和长期存储(可选)。
📣 配置 Alertmanager
首先,在 prometheus.yml 中配置 Alertmanager 地址:
alerting:
alertmanagers:
- static_configs:
- targets: ['alertmanager:9093']
然后定义告警规则(alert.rules.yml):
groups:
- name: example
rules:
- alert: HighOrderFailureRate
expr: rate(orders_created_total{status="failure"}[5m]) / rate(orders_created_total[5m]) > 0.1
for: 2m
labels:
severity: critical
annotations:
summary: "High order failure rate on {{ $labels.instance }}"
description: "Order failure rate is above 10% for more than 2 minutes."
在 prometheus.yml 中加载规则文件:
rule_files:
- "alert.rules.yml"
启动 Alertmanager(使用默认配置即可):
docker run -d --name=alertmanager -p 9093:9093 prom/alertmanager
当订单失败率持续 2 分钟超过 10%,Prometheus 会触发告警并发送给 Alertmanager。
使用 Grafana 可视化指标
虽然 Prometheus 自带简单的图形界面,但 Grafana 提供了更强大、更美观的可视化能力。
🎨 启动 Grafana
docker run -d --name=grafana -p 3000:3000 grafana/grafana
访问 http://localhost:3000,默认账号密码为 admin/admin。
🔗 添加 Prometheus 数据源
- 进入 Configuration > Data Sources。
- 点击 Add data source,选择 Prometheus。
- URL 填写
http://host.docker.internal:9090(根据你的环境调整)。 - 点击 Save & Test。
📊 创建仪表盘
点击 Create > Dashboard,添加一个 Panel:
- Query:输入
rate(orders_created_total[5m]) - Legend:
{{status}} - Visualization:选择 Time series
你将看到成功和失败订单的实时速率曲线。
🌐 Grafana 官方提供了大量社区贡献的仪表盘模板,例如 Spring Boot Dashboard,可直接导入使用。
高级技巧与最佳实践
🏷️ 标签(Labels)设计原则
标签是 Prometheus 多维数据模型的核心,但滥用会导致高基数问题(High Cardinality),消耗大量内存。
错误示例:
// 不要将用户ID、请求ID等高基数字段作为标签!
Counter.builder("user_login_attempts")
.tag("user_id", userId) // ❌ 高基数!
.register(registry);
正确做法:
- 仅使用低基数、有聚合意义的标签,如
status、region、service。 - 对于高基数数据,考虑使用日志系统(如 ELK)或分布式追踪(如 Jaeger)。
📉 Histogram vs Summary
Micrometer 默认使用 Histogram 来记录 Timer 和 Distribution Summary。Histogram 在客户端预计算分位数桶(buckets),而 Summary 在服务端计算精确分位数。
Histogram 优势:
- 支持跨实例聚合(
sum(rate(...)))。 - 存储开销固定(由 bucket 数量决定)。
配置自定义 buckets:
Timer.builder("payment_processing_duration_seconds")
.publishPercentiles(0.5, 0.95, 0.99) // 客户端分位数(不推荐跨实例聚合)
.publishPercentileHistogram() // 发布 histogram buckets
.serviceLevelObjectives(Duration.ofMillis(100), Duration.ofMillis(500)) // SLO buckets
.register(meterRegistry);
在 application.yml 中全局配置:
management:
metrics:
distribution:
percentiles-histogram:
http.server.requests: true # 为 HTTP 请求启用 histogram
slo:
http.server.requests: 100ms, 500ms, 1s # 定义 SLO buckets
🔄 动态刷新配置
在 Kubernetes 环境中,服务实例动态变化。Prometheus 支持多种服务发现机制:
- Kubernetes SD:自动发现 Pod、Service。
- Consul SD:通过 Consul 服务注册中心发现。
- DNS SD:通过 DNS SRV 记录发现。
例如,Kubernetes 配置片段:
scrape_configs:
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
只需在 Pod 的 annotation 中添加:
annotations:
prometheus.io/scrape: "true"
prometheus.io/path: "/actuator/prometheus"
prometheus.io/port: "8080"
故障排查常见问题
❓ 问题1:Prometheus 抓取目标状态为 DOWN
可能原因:
- 网络不通(防火墙、容器网络)。
- Spring Boot 应用未暴露
/actuator/prometheus。 - 应用未启动或端口错误。
排查步骤:
- 在 Prometheus 容器内执行
curl http://target:port/actuator/prometheus。 - 检查 Spring Boot 日志是否有 Actuator 端点注册信息。
- 确认
management.endpoints.web.exposure.include包含prometheus。
❓ 问题2:指标缺失或标签不全
可能原因:
- Micrometer 未正确注册指标。
- 自定义指标作用域错误(如局部变量导致 GC)。
解决方案:
- 确保指标对象是成员变量(而非方法内局部变量)。
- 使用
MeterRegistry.find()调试指标是否存在。
// 调试:检查指标是否注册
List<Meter> meters = meterRegistry.find("orders_created_total").meters();
System.out.println("Found " + meters.size() + " meters");
❓ 问题3:高内存使用
可能原因:
- 高基数标签导致时序数量爆炸。
- Prometheus 保留时间过长。
解决方案:
- 使用
tsdb命令分析时序基数:docker exec prometheus tsdb analyze /prometheus - 在
prometheus.yml中限制保留时间:global: retention_time: 15d # 仅保留15天数据
总结与展望
通过本文,我们系统地学习了如何在 Spring Boot 微服务中集成 Prometheus 监控:
- 基础集成:通过 Actuator 和 Micrometer 暴露自动指标。
- 自定义指标:使用 Counter、Timer、Gauge 等 API 监控业务逻辑。
- Prometheus 配置:抓取指标、定义告警规则。
- 可视化与告警:使用 Grafana 展示数据,Alertmanager 发送通知。
- 最佳实践:避免高基数、合理设计标签、利用服务发现。
监控不是一次性工程,而是一个持续迭代的过程。随着业务发展,你需要不断调整指标、优化告警策略、完善仪表盘。
🔮 未来方向
- OpenTelemetry 集成:OpenTelemetry 正在统一指标、日志、追踪三大支柱。Spring Boot 3 已开始支持 OpenTelemetry。
- Serverless 监控:在 AWS Lambda、Azure Functions 等无服务器环境中,指标暴露方式有所不同。
- AIOps:结合机器学习,实现异常检测、根因分析等智能运维能力。
🌟 最后建议:不要为了监控而监控。始终围绕业务目标和 SLO(Service Level Objectives)来设计你的监控体系。正如 Google SRE 书中所言:“监控系统应该回答‘系统是否正常?’这个问题。”
Happy Monitoring! 🚀
🙌 感谢你读到这里!
🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。
💡 如果本文对你有帮助,不妨 👍 点赞、📌 收藏、📤 分享 给更多需要的朋友!
💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿
🔔 关注我,不错过下一篇干货!我们下期再见!✨
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)