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

👋 大家好,欢迎来到我的技术博客!

📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。

🎯 本文将围绕Prometheus 这个话题展开,希望能为你带来一些启发或实用的参考。

🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获!


文章目录

  • [Prometheus - 监控微服务:Spring Boot 应用指标暴露与监控](#Prometheus - 监控微服务:Spring Boot 应用指标暴露与监控)
    • [为什么需要监控 Spring Boot 微服务?](#为什么需要监控 Spring Boot 微服务?)
      • [🔍 常见痛点](#🔍 常见痛点)
      • [📊 监控的价值](#📊 监控的价值)
    • [Prometheus 核心概念速览](#Prometheus 核心概念速览)
      • [📈 时序数据(Time Series)](#📈 时序数据(Time Series))
      • [🕵️‍♂️ 拉取模型(Pull Model)](#🕵️‍♂️ 拉取模型(Pull Model))
      • [🔧 PromQL:强大的查询语言](#🔧 PromQL:强大的查询语言)
      • [📣 Alertmanager:告警管理](#📣 Alertmanager:告警管理)
    • [在 Spring Boot 中暴露 Prometheus 指标](#在 Spring Boot 中暴露 Prometheus 指标)
      • [🛠️ 步骤一:添加依赖](#🛠️ 步骤一:添加依赖)
      • [🌐 步骤二:启用 Prometheus 端点](#🌐 步骤二:启用 Prometheus 端点)
    • 自动收集的指标详解
      • [🖥️ JVM 指标](#🖥️ JVM 指标)
      • [🌐 Web 指标](#🌐 Web 指标)
      • [📦 缓存与数据源指标](#📦 缓存与数据源指标)
    • 自定义业务指标
      • [📏 指标类型](#📏 指标类型)
      • [✨ 示例:监控订单创建](#✨ 示例:监控订单创建)
      • [⏱️ 示例:记录方法执行时间](#⏱️ 示例:记录方法执行时间)
      • [📊 示例:动态 Gauge(如队列长度)](#📊 示例:动态 Gauge(如队列长度))
    • [配置 Prometheus 抓取 Spring Boot 指标](#配置 Prometheus 抓取 Spring Boot 指标)
      • [📄 prometheus.yml 配置](#📄 prometheus.yml 配置)
      • [🚀 启动 Prometheus](#🚀 启动 Prometheus)
      • [🔍 查询指标](#🔍 查询指标)
    • 构建完整的监控架构
      • [🧩 架构组件](#🧩 架构组件)
      • [📣 配置 Alertmanager](#📣 配置 Alertmanager)
    • [使用 Grafana 可视化指标](#使用 Grafana 可视化指标)
      • [🎨 启动 Grafana](#🎨 启动 Grafana)
      • [🔗 添加 Prometheus 数据源](#🔗 添加 Prometheus 数据源)
      • [📊 创建仪表盘](#📊 创建仪表盘)
    • 高级技巧与最佳实践
      • [🏷️ 标签(Labels)设计原则](#🏷️ 标签(Labels)设计原则)
      • [📉 Histogram vs Summary](#📉 Histogram vs Summary)
      • [🔄 动态刷新配置](#🔄 动态刷新配置)
    • 故障排查常见问题
      • [❓ 问题1:Prometheus 抓取目标状态为 DOWN](#❓ 问题1:Prometheus 抓取目标状态为 DOWN)
      • [❓ 问题2:指标缺失或标签不全](#❓ 问题2:指标缺失或标签不全)
      • [❓ 问题3:高内存使用](#❓ 问题3:高内存使用)
    • 总结与展望
      • [🔮 未来方向](#🔮 未来方向)

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) 的函数式查询语言,支持聚合、过滤、数学运算等操作。例如:

promql 复制代码
# 查询过去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 中添加以下依赖:

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 端点:

yaml 复制代码
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 记录事件大小分布 响应体大小、消息队列长度

✨ 示例:监控订单创建

假设我们有一个订单服务,希望跟踪成功和失败的订单创建次数。

java 复制代码
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 记录关键方法的执行时间:

java 复制代码
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 通常用于反映当前状态。例如,监控一个工作队列的长度:

java 复制代码
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 文件:

yaml 复制代码
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:

bash 复制代码
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 查询框中输入:

promql 复制代码
# 查看所有订单创建指标
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 的 ignoringgroup_left 用于处理标签不匹配的向量匹配,详见 Prometheus 向量匹配文档


构建完整的监控架构

在生产环境中,单个 Prometheus 实例可能不足以应对大规模微服务集群。我们需要考虑高可用、长期存储、告警等高级特性。

🧩 架构组件

一个典型的 Prometheus 监控栈包含以下组件:
#mermaid-svg-UGqUibJdJPoTUwyz{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-UGqUibJdJPoTUwyz .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-UGqUibJdJPoTUwyz .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-UGqUibJdJPoTUwyz .error-icon{fill:#552222;}#mermaid-svg-UGqUibJdJPoTUwyz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-UGqUibJdJPoTUwyz .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-UGqUibJdJPoTUwyz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-UGqUibJdJPoTUwyz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-UGqUibJdJPoTUwyz .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-UGqUibJdJPoTUwyz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-UGqUibJdJPoTUwyz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-UGqUibJdJPoTUwyz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-UGqUibJdJPoTUwyz .marker.cross{stroke:#333333;}#mermaid-svg-UGqUibJdJPoTUwyz svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-UGqUibJdJPoTUwyz p{margin:0;}#mermaid-svg-UGqUibJdJPoTUwyz .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-UGqUibJdJPoTUwyz .cluster-label text{fill:#333;}#mermaid-svg-UGqUibJdJPoTUwyz .cluster-label span{color:#333;}#mermaid-svg-UGqUibJdJPoTUwyz .cluster-label span p{background-color:transparent;}#mermaid-svg-UGqUibJdJPoTUwyz .label text,#mermaid-svg-UGqUibJdJPoTUwyz span{fill:#333;color:#333;}#mermaid-svg-UGqUibJdJPoTUwyz .node rect,#mermaid-svg-UGqUibJdJPoTUwyz .node circle,#mermaid-svg-UGqUibJdJPoTUwyz .node ellipse,#mermaid-svg-UGqUibJdJPoTUwyz .node polygon,#mermaid-svg-UGqUibJdJPoTUwyz .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-UGqUibJdJPoTUwyz .rough-node .label text,#mermaid-svg-UGqUibJdJPoTUwyz .node .label text,#mermaid-svg-UGqUibJdJPoTUwyz .image-shape .label,#mermaid-svg-UGqUibJdJPoTUwyz .icon-shape .label{text-anchor:middle;}#mermaid-svg-UGqUibJdJPoTUwyz .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-UGqUibJdJPoTUwyz .rough-node .label,#mermaid-svg-UGqUibJdJPoTUwyz .node .label,#mermaid-svg-UGqUibJdJPoTUwyz .image-shape .label,#mermaid-svg-UGqUibJdJPoTUwyz .icon-shape .label{text-align:center;}#mermaid-svg-UGqUibJdJPoTUwyz .node.clickable{cursor:pointer;}#mermaid-svg-UGqUibJdJPoTUwyz .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-UGqUibJdJPoTUwyz .arrowheadPath{fill:#333333;}#mermaid-svg-UGqUibJdJPoTUwyz .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-UGqUibJdJPoTUwyz .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-UGqUibJdJPoTUwyz .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-UGqUibJdJPoTUwyz .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-UGqUibJdJPoTUwyz .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-UGqUibJdJPoTUwyz .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-UGqUibJdJPoTUwyz .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-UGqUibJdJPoTUwyz .cluster text{fill:#333;}#mermaid-svg-UGqUibJdJPoTUwyz .cluster span{color:#333;}#mermaid-svg-UGqUibJdJPoTUwyz div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-UGqUibJdJPoTUwyz .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-UGqUibJdJPoTUwyz rect.text{fill:none;stroke-width:0;}#mermaid-svg-UGqUibJdJPoTUwyz .icon-shape,#mermaid-svg-UGqUibJdJPoTUwyz .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-UGqUibJdJPoTUwyz .icon-shape p,#mermaid-svg-UGqUibJdJPoTUwyz .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-UGqUibJdJPoTUwyz .icon-shape .label rect,#mermaid-svg-UGqUibJdJPoTUwyz .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-UGqUibJdJPoTUwyz .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-UGqUibJdJPoTUwyz .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-UGqUibJdJPoTUwyz :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Exposes /actuator/prometheus
Scrapes Metrics
Sends Alerts
Notifies via Email/Slack
Stores Time Series
Remote Write
Queries
Visualizes Dashboards
Spring Boot App
Prometheus Server
Alertmanager
On-Call Engineer
Local TSDB
Thanos/Cortex for Long-Term Storage
Grafana
User

  • Prometheus Server:核心组件,负责抓取、存储、查询。
  • Alertmanager:处理告警路由和通知。
  • Grafana:可视化面板,提供比 Prometheus 更丰富的图表。
  • Thanos/Cortex:用于跨集群聚合和长期存储(可选)。

📣 配置 Alertmanager

首先,在 prometheus.yml 中配置 Alertmanager 地址:

yaml 复制代码
alerting:
  alertmanagers:
    - static_configs:
        - targets: ['alertmanager:9093']

然后定义告警规则(alert.rules.yml):

yaml 复制代码
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 中加载规则文件:

yaml 复制代码
rule_files:
  - "alert.rules.yml"

启动 Alertmanager(使用默认配置即可):

bash 复制代码
docker run -d --name=alertmanager -p 9093:9093 prom/alertmanager

当订单失败率持续 2 分钟超过 10%,Prometheus 会触发告警并发送给 Alertmanager。


使用 Grafana 可视化指标

虽然 Prometheus 自带简单的图形界面,但 Grafana 提供了更强大、更美观的可视化能力。

🎨 启动 Grafana

bash 复制代码
docker run -d --name=grafana -p 3000:3000 grafana/grafana

访问 http://localhost:3000,默认账号密码为 admin/admin

🔗 添加 Prometheus 数据源

  1. 进入 Configuration > Data Sources
  2. 点击 Add data source ,选择 Prometheus
  3. URL 填写 http://host.docker.internal:9090(根据你的环境调整)。
  4. 点击 Save & Test

📊 创建仪表盘

点击 Create > Dashboard,添加一个 Panel:

  • Query :输入 rate(orders_created_total[5m])
  • Legend{``{status}}
  • Visualization:选择 Time series

你将看到成功和失败订单的实时速率曲线。

🌐 Grafana 官方提供了大量社区贡献的仪表盘模板,例如 Spring Boot Dashboard,可直接导入使用。


高级技巧与最佳实践

🏷️ 标签(Labels)设计原则

标签是 Prometheus 多维数据模型的核心,但滥用会导致高基数问题(High Cardinality),消耗大量内存。

错误示例

java 复制代码
// 不要将用户ID、请求ID等高基数字段作为标签!
Counter.builder("user_login_attempts")
       .tag("user_id", userId) // ❌ 高基数!
       .register(registry);

正确做法

  • 仅使用低基数、有聚合意义的标签,如 statusregionservice
  • 对于高基数数据,考虑使用日志系统(如 ELK)或分布式追踪(如 Jaeger)。

📉 Histogram vs Summary

Micrometer 默认使用 Histogram 来记录 Timer 和 Distribution Summary。Histogram 在客户端预计算分位数桶(buckets),而 Summary 在服务端计算精确分位数。

Histogram 优势

  • 支持跨实例聚合(sum(rate(...)))。
  • 存储开销固定(由 bucket 数量决定)。

配置自定义 buckets

java 复制代码
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 中全局配置:

yaml 复制代码
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 配置片段:

yaml 复制代码
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 中添加:

yaml 复制代码
annotations:
  prometheus.io/scrape: "true"
  prometheus.io/path: "/actuator/prometheus"
  prometheus.io/port: "8080"

故障排查常见问题

❓ 问题1:Prometheus 抓取目标状态为 DOWN

可能原因

  • 网络不通(防火墙、容器网络)。
  • Spring Boot 应用未暴露 /actuator/prometheus
  • 应用未启动或端口错误。

排查步骤

  1. 在 Prometheus 容器内执行 curl http://target:port/actuator/prometheus
  2. 检查 Spring Boot 日志是否有 Actuator 端点注册信息。
  3. 确认 management.endpoints.web.exposure.include 包含 prometheus

❓ 问题2:指标缺失或标签不全

可能原因

  • Micrometer 未正确注册指标。
  • 自定义指标作用域错误(如局部变量导致 GC)。

解决方案

  • 确保指标对象是成员变量(而非方法内局部变量)。
  • 使用 MeterRegistry.find() 调试指标是否存在。
java 复制代码
// 调试:检查指标是否注册
List<Meter> meters = meterRegistry.find("orders_created_total").meters();
System.out.println("Found " + meters.size() + " meters");

❓ 问题3:高内存使用

可能原因

  • 高基数标签导致时序数量爆炸。
  • Prometheus 保留时间过长。

解决方案

  • 使用 tsdb 命令分析时序基数:

    bash 复制代码
    docker exec prometheus tsdb analyze /prometheus
  • prometheus.yml 中限制保留时间:

    yaml 复制代码
    global:
      retention_time: 15d  # 仅保留15天数据

总结与展望

通过本文,我们系统地学习了如何在 Spring Boot 微服务中集成 Prometheus 监控:

  1. 基础集成:通过 Actuator 和 Micrometer 暴露自动指标。
  2. 自定义指标:使用 Counter、Timer、Gauge 等 API 监控业务逻辑。
  3. Prometheus 配置:抓取指标、定义告警规则。
  4. 可视化与告警:使用 Grafana 展示数据,Alertmanager 发送通知。
  5. 最佳实践:避免高基数、合理设计标签、利用服务发现。

监控不是一次性工程,而是一个持续迭代的过程。随着业务发展,你需要不断调整指标、优化告警策略、完善仪表盘。

🔮 未来方向

  • OpenTelemetry 集成:OpenTelemetry 正在统一指标、日志、追踪三大支柱。Spring Boot 3 已开始支持 OpenTelemetry。
  • Serverless 监控:在 AWS Lambda、Azure Functions 等无服务器环境中,指标暴露方式有所不同。
  • AIOps:结合机器学习,实现异常检测、根因分析等智能运维能力。

🌟 最后建议 :不要为了监控而监控。始终围绕业务目标和 SLO(Service Level Objectives)来设计你的监控体系。正如 Google SRE 书中所言:"监控系统应该回答'系统是否正常?'这个问题。"

Happy Monitoring! 🚀


🙌 感谢你读到这里!

🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。

💡 如果本文对你有帮助,不妨 👍 点赞 、📌 收藏 、📤 分享 给更多需要的朋友!

💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿

🔔 关注我,不错过下一篇干货!我们下期再见!✨

相关推荐
一条小锦吕*1 小时前
基于Spring Boot + 数据可视化 + 协同过滤算法的推荐系统设计与实现(源码+论文+部署全讲解)
spring boot·算法·信息可视化
码农阿豪1 小时前
从零到一:Spring Boot快速接入金仓数据库实战
数据库·spring boot·后端
郑洁文6 小时前
基于SpringBoot的商品仓库管理系统的设计与实现
java·spring boot·后端·仓库管理系统·商品仓库管理系统
云烟成雨TD7 小时前
Spring AI 1.x 系列【50】可观测性:接入 Prometheus + Grafana
人工智能·spring·prometheus
小云小白11 小时前
企业抗量子落地指南(一)全链路抗量子 TLS1.3 落地指南(浏览器 → Nginx → SpringBoot)
spring boot·nginx·抗量子通信
心之伊始11 小时前
Spring AI MCP Client 实战:让 Java 后端通过 stdio 调用本地工具服务
java·spring boot·agent·spring ai·mcp
元宝骑士11 小时前
SpringBoot + Sa-Token 实现浏览器级 CSRF 防御(基础篇)
spring boot·安全
sbjdhjd11 小时前
04(上)| k8s中的微服务
微服务·云原生·kubernetes·开源·云计算·excel·kubelet
qq_25183645711 小时前
2026计算机毕设选题|3000套高质量SpringBoot实战项目(含完整源码)(每人一套不收米)
java·spring boot·课程设计