【性能监控 APM 六】Micrometer&actuator

SpringBoot 监控指标框架体系原理、核心组件、API、完整实战示例

一、整体体系概览

SpringBoot 监控体系核心:Spring Boot Actuator + Micrometer(指标门面)

历史版本区分

  1. SpringBoot1.x:Actuator底层直接使用Metrics(废弃)
  2. SpringBoot2.x+:Micrometer作为统一指标API门面(核心标准)
    架构分层自上而下:
应用业务代码 → Micrometer API(统一指标接口)
       ↓
Micrometer实现(Prometheus/PrometheusMeterRegistry、Influx、JMX等)
       ↓
SpringBoot Actuator:对外暴露端点(/actuator/prometheus、/actuator/metrics)
       ↓
监控采集端:Prometheus → Grafana可视化;ELK;AlertManager告警

核心概念区分

  1. Actuator:提供运维端点(健康检查、指标、线程dump、环境信息),不是指标实现,是HTTP暴露层
  2. Micrometer:指标标准门面,类似SLF4j(日志门面);屏蔽不同监控系统API差异
  3. Meter:Micrometer中所有指标的统称,包含5大类型
  4. Registry(MeterRegistry):指标注册表,保存所有指标,对接具体监控系统

二、底层原理

1. Micrometer核心设计思想

门面模式
业务代码只依赖 io.micrometer 标准API,不需要绑定Prometheus/InfluxDB。切换监控系统只需要引入对应依赖、配置,业务代码零改动。

业务 → MeterRegistry(接口) ←———
                          |
        PrometheusMeterRegistry / SimpleMeterRegistry / JmxMeterRegistry

SpringBoot自动装配机制:
MeterRegistryAutoConfiguration
自动注入全局MeterRegistry(CompositeMeterRegistry,组合多个Registry)

2. 自动指标采集(内置埋点)

SpringBoot自动注册大量内置指标,无需开发:

  • JVM:堆内存、非堆内存、GC次数、GC耗时、线程数、类加载
  • Tomcat/Undertow:http请求耗时、请求数量、错误码、活跃连接
  • Spring MVC:接口调用指标
  • JDBC(HikariCP):连接池活跃连接、等待队列、超时
  • Logback:日志打印计数(error/warn/info)

3. Actuator工作原理

Actuator 通过Endpoint组件定义监控能力;
通过WebEndpointServlet/WebFlux适配器,将端点暴露为HTTP接口;

  • /actuator/health 健康检查
  • /actuator/metrics 原始micrometer指标
  • /actuator/prometheus 适配Prometheus文本格式指标(最常用)

三、Meter五大指标类型(重点!属性与方法)

Micrometer 定义5种标准指标,每种指标适用场景严格区分

所有指标支持 Tag(标签) = 维度,用于多维度筛选(接口路径、异常类型、实例ip、环境)

指标类型 作用 典型场景
Counter 计数器 只增不减,仅记录总量 请求次数、错误次数、消息消费数量
Gauge 仪表盘 瞬时值,可增可减 当前活跃连接数、在线用户、队列长度、内存占用
Timer 计时器 记录事件耗时+调用次数 HTTP接口耗时、方法执行耗时
DistributionSummary 分布摘要 记录大小分布(无时间维度) 上传文件大小、报文长度
LongTaskTimer 长任务计时器 记录正在运行任务时长 异步任务、长时间运行任务(批处理)

公共基础概念:Tag(维度标签)

Tag.of("uri", "/api/order/create");
Tag.of("status", "200");
// 推荐常量方式,避免字符串硬编码

Prometheus最佳实践:标签不要过多(基数爆炸cardinality风险!避免传入userId、orderId这类无限唯一值)


四、每种指标:核心API、属性、使用示例

前置Maven依赖(SpringBoot3.x,jakarta;2.x保持javax)

<!-- SpringBoot Actuator核心 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- prometheus格式导出(生产主流) -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

application.yml 基础配置

management:
  endpoints:
    web:
      exposure:
        include: health,prometheus,metrics
  metrics:
    tags:
      application: ${spring.application.name} #全局标签:应用名
  endpoint:
    health:
      show-details: always

1. Counter 计数器

特点:只能increment(),不能减少;适合统计总量
核心方法

// 创建
Counter counter = registry.counter("order.create.total", Tags.of("status", "success"));
// +1
counter.increment();
// +n
counter.increment(5);
// 获取当前值
counter.count();

完整使用示例

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

@Service
public class OrderService {
    @Resource
    private MeterRegistry meterRegistry;

    public void createOrder(Boolean success) {
        Tags tags = Tags.of("status", success ? "success" : "fail");
        Counter counter = meterRegistry.counter("order.create.count", tags);
        counter.increment();
    }
}

2. Gauge 仪表盘(瞬时指标)

特点:获取瞬时数值,不自动记录变化;适合表达当前状态

⚠️重点坑:Gauge不会主动回调,registry定时轮询取值;不要使用频繁创建对象

两种注册方式
方式1:Lambda 动态取值(推荐)

// 模拟队列
private final Queue<String> taskQueue = new ConcurrentLinkedQueue<>();

// Bean初始化时注册一次
@PostConstruct
public void registerGauge() {
    meterRegistry.gauge("task.queue.size", Tags.empty(), taskQueue, Queue::size);
}

方式2:AtomicReference包装可变数值

AtomicInteger onlineUser = new AtomicInteger(0);
meterRegistry.gauge("online.user.count", Tags.empty(), onlineUser, AtomicInteger::get);
onlineUser.set(120);

禁止写法:

// ❌错误!每次调用新建Gauge,内存泄漏
public void test(){
    meterRegistry.gauge("xxx", Tags.empty(), ()-> getValue());
}

3. Timer 计时器(最常用)

特点:统计事件耗时、调用次数,自动生成:总次数、平均耗时、最大最小、百分位p95/p99
两种使用模式

模式1:record(Runnable) 自动计时

Timer timer = meterRegistry.timer("order.pay.time", Tags.of("payType", "alipay"));
timer.record(this::payOrder);

模式2:手动控制开始结束

Timer.Sample sample = Timer.start(meterRegistry);
try {
    payOrder();
} finally {
    sample.stop(timer);
}

开启百分位配置(yml)

management.metrics.distribution.percentiles-histogram.order.pay.time: true

开启后Prometheus可以计算p95、p99延迟

4. DistributionSummary 分布摘要

无时间维度,统计数据大小(报文大小、文件尺寸)

DistributionSummary summary = meterRegistry.summary("http.response.size", Tags.of("uri", "/api/file/upload"));
// 记录数值(单位byte)
summary.record(1024);
summary.record(2048);

5. LongTaskTimer 长耗时任务

监控正在执行的任务,区分普通Timer(普通Timer任务结束才记录)
指标包含:活跃任务数、正在运行任务总时长

LongTaskTimer taskTimer = meterRegistry.longTaskTimer("batch.task.running", Tags.of("taskName", "sync_data"));

LongTaskTimer.Sample sample = taskTimer.start();
try{
    //长时间批任务
}finally {
    sample.stop();
}

五、三种埋点方案对比(业务开发可选)

方案1:原生Micrometer API(上面示例,灵活可控)

方案2:AOP + @Timed 注解(无侵入,推荐接口监控)

依赖spring-aop,直接注解方法自动生成Timer指标

import io.micrometer.core.annotation.Timed;

@Service
public class OrderService {
    @Timed(value = "order.create.method.time", percentiles = {0.5,0.95,0.99})
    public void createOrder() {
        //业务逻辑
    }
}

⚠️默认SpringBoot只对Controller生效!Service需要手动开启TimedAop

@Configuration
@EnableAspectJAutoProxy
public class MetricConfig {
    @Bean
    public TimedAspect timedAspect(MeterRegistry registry) {
        return new TimedAspect(registry);
    }
}

方案3:自动采集(零代码)

SpringMVC接口、连接池、JVM指标,不需要写任何代码,启动自动采集
访问 http://127.0.0.1:8080/actuator/metrics/http.server.requests 查看web请求指标

六、Actuator端点详解

常用端点

端点 作用
/actuator/health 健康检查,存活探测(k8s liveness/readiness)
/actuator/prometheus 输出prometheus格式指标【生产必开】
/actuator/metrics 原始json格式指标(调试用)
/actuator/info 应用版本信息

访问地址示例:
http://localhost:8080/actuator/prometheus

七、完整工程Demo结构

MetricConfig 统一指标配置(全局通用标签、百分位、过滤)

import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.config.MeterFilter;
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MetricConfig {

    // 全局统一tag
    @Bean
    public MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
        return registry -> registry.config()
                .commonTags("application", "order-service");
    }

    // 开启所有timer直方图(可按需限制指标名)
    @Bean
    public MeterRegistryCustomizer<MeterRegistry> enablePercentile() {
        return registry -> registry.config()
                .meterFilter(MeterFilter.maxExpected("http.server.requests", Duration.ofSeconds(5)))
                .meterFilter(MeterFilter.publishPercentileHistogram());
    }
}

八、生产常见坑 & 最佳实践

1. 基数爆炸(Cardinality 严重问题)

❌错误:tag放入唯一值

//禁止!每个订单一个tag,指标无限膨胀
Tags.of("orderId",orderId.toString())

✅正确:tag使用有限枚举:status、errorCode、uri、payType

2. Gauge 频繁创建导致内存泄漏

Gauge注册后不要循环创建,放在@PostConstruct一次性注册

3. Timer百分位不生效

需要开启 publishPercentileHistogram=true,否则prometheus无法计算p95/p99

4. /actuator/prometheus 404

yml没有暴露端点:

management.endpoints.web.exposure.include: health,prometheus

5. 区分SimpleMeterRegistry vs PrometheusMeterRegistry

  • SimpleMeterRegistry:内存指标,重启丢失(单元测试)
  • PrometheusMeterRegistry:适配Prometheus文本格式,生产使用

九、完整监控链路演示

应用(SpringBoot) → /actuator/prometheus
→ Prometheus定时拉取指标
→ Grafana配置图表(延迟、QPS、错误率、JVM内存)
→ AlertManager配置告警(错误率>5%、接口p99延迟过高)

十、拓展方向(需要我可以补充完整代码)

  1. Prometheus + Grafana 监控面板模板导入
  2. 自定义健康指示器 HealthIndicator
  3. 线程池、Redis模板自动埋点封装
  4. 全局统一异常指标AOP封装
  5. SpringBoot3 与 SpringBoot2 Micrometer差异
  6. 指标推拉模式(PushGateway主动推送 vs Prometheus拉取)

如果你需要,我可以直接提供一套可复制:全局接口监控AOP、异常计数器、线程池指标埋点完整工具类

posted @ 2026-07-29 17:44  蓝迷梦  阅读(3)  评论(0)    收藏  举报