Micrometer 系列【25】Spring Boot Actuator | Spring MVC、Spring WebFlux 指标

文章目录

  • [1. Spring MVC 指标](#1. Spring MVC 指标)
    • [1.1 查看指标](#1.1 查看指标)
      • [1.1.1 http.server.requests](#1.1.1 http.server.requests)
      • [1.1.2 http.server.requests](#1.1.2 http.server.requests)
    • [2.2 自定义指标名称](#2.2 自定义指标名称)
    • [2.3 追加自定义标签](#2.3 追加自定义标签)
      • [2.3.1 方式 1:追加标签](#2.3.1 方式 1:追加标签)
      • [2.3.2 方式 2:完全替换全部标签](#2.3.2 方式 2:完全替换全部标签)
    • [2.4 把已捕获异常埋入指标标签](#2.4 把已捕获异常埋入指标标签)
    • [2.5 自定义过滤:跳过部分请求不采集指标](#2.5 自定义过滤:跳过部分请求不采集指标)
  • [2. Spring WebFlux 指标](#2. Spring WebFlux 指标)

1. Spring MVC 指标

自动配置会对所有由 Spring MVC 控制器、函数式处理器处理的请求做指标埋点。默认生成指标名称为 http.server.requests

1.1 查看指标

/actuator/metrics 包含两个指标名:

java 复制代码
    "http.server.requests",
    "http.server.requests.active",

1.1.1 http.server.requests

基于 Micrometer Observation 生成的 HTTP 请求计时器指标,baseUnit 单位为 seconds(秒)。

返回示例:

json 复制代码
{
  "availableTags": [
    {
      "tag": "exception",
      "values": [
        "none"
      ]
    },
    {
      "tag": "method",
      "values": [
        "GET"
      ]
    },
    {
      "tag": "error",
      "values": [
        "none"
      ]
    },
    {
      "tag": "uri",
      "values": [
        "/actuator/metrics/{requiredMetricName}",
        "/actuator/metrics",
        "/actuator/prometheus",
        "/api/redis/{key}"
      ]
    },
    {
      "tag": "outcome",
      "values": [
        "SUCCESS"
      ]
    },
    {
      "tag": "status",
      "values": [
        "200"
      ]
    }
  ],
  "baseUnit": "seconds",
  "measurements": [
    {
      "statistic": "COUNT",
      "value": 117
    },
    {
      "statistic": "TOTAL_TIME",
      "value": 2.992938
    },
    {
      "statistic": "MAX",
      "value": 0.0297637
    }
  ],
  "name": "http.server.requests"
}

整体字段概览:

字段 说明
name 指标名称:http.server.requests,服务端HTTP请求计时器
baseUnit 基础单位:seconds
availableTags 该指标可用标签集合,代表会出现在 Prometheus 里的标签维度以及采样到的枚举值示例
measurements 度量统计值:COUNT总请求数、TOTAL_TIME总耗时、MAX最大耗时

availableTags 标签解读:

tag标签 示例values 含义
exception none 请求抛出的异常类名;none=无异常抛出
method GET HTTP 请求方法:GET/POST/PUT/DELETE...
error none 错误标识;none=业务无错误;发生异常时为异常类名
uri /actuator/metrics/{requiredMetricName} /actuator/metrics /actuator/prometheus /api/redis/{key} 模板化URI,不是真实路径变量值,路径中的变量被大括号占位,防止标签爆炸
outcome SUCCESS 请求结果枚举:SUCCESS/CLIENT_ERROR/SERVER_ERROR/REDIRECTION,由HTTP状态码推导
status 200 HTTP响应状态码字符串,如 200404500

⚠️注意:values 只是当前采样看到的取值,不是全部枚举全集,是实例已经采集到的值。

measurements 度量数据:

statistic统计类型 value值 释义
COUNT 117 总请求次数:一共117次http请求
TOTAL_TIME 2.992938 全部请求累加总耗时,单位秒:117次请求合计耗时约2.99秒
MAX 0.0297637 这一批采样窗口内最大单次请求耗时,约29.76毫秒

/metrics端点返回的是内存中快照;导出到 Prometheus 后会拆分为 3个指标:

  • http_server_requests_seconds_count 请求计数
  • http_server_requests_seconds_sum 总耗时
  • http_server_requests_seconds_max 最大耗时

1.1.2 http.server.requests

活跃请求计时器指标 ,用于观测正在处理中尚未完成的 HTTP 请求 ,和普通 http.server.requests(已完成请求)是一对指标。

访问 /actuator/metrics/http.server.requests.active 获取该快照,baseUnit: seconds 单位为秒。

字段总览:

字段 说明
name http.server.requests.active,服务端活跃HTTP请求指标,跟踪运行中未结束请求
baseUnit seconds,时间单位:秒
availableTags 可用标签集合,values为当前实例已经采集到的样本值
measurements 度量统计:ACTIVE_TASKS活跃并发数、DURATION累计耗时、MAX最大处理时长

availableTags 标签解读:

tag标签 示例values 含义
exception none 活跃请求发生异常;活跃阶段一般不会产生异常,几乎总是none
method GET HTTP请求方法
uri UNKNOWN 无法解析控制器映射模板时标记为UNKNOWN ;常见原因:404无匹配接口、过滤器提前拦截、静态资源、未走到控制器路由解析逻辑,会打uri=UNKNOWN标签,防止高基数标签爆炸
outcome SUCCESS 请求处理结果;活跃请求该标签意义有限,最终结果要等请求结束看http.server.requests
status 200 HTTP响应码;活跃请求此时响应码还未完全确定,参考价值低

values 仅代表当前已经观测到的值,不是全部枚举集合。
⚠️重点:uri=UNKNOWN ,请求还没匹配到控制器模板就已经结束/被拦截,拿不到模板URI,就会标记为UNKNOWN。比如 404filter 直接 response 返回、静态资源、网关层提前终止请求。

measurements 统计值解读:

statistic统计类型 value 释义
ACTIVE_TASKS 1 当前并发活跃请求数:此刻有1个HTTP请求正在处理中,还未返回响应
DURATION 0.0024552 所有已完成的活跃任务的累计总耗时(秒)
MAX 0.002476 观测周期内,活跃请求曾经出现过的最大处理耗时,约2.476毫秒

和普通 http.server.requests 的核心区别:

指标 用途 统计的请求 主要统计项
http.server.requests 已完成请求统计 请求处理完毕(成功/异常) COUNT、TOTAL_TIME、MAX;用于QPS、延迟、错误率
http.server.requests.active 活跃并发观测 正在运行、还没结束的请求 ACTIVE_TASKS(并发数)、DURATION、MAX;用于观测瞬时并发、慢请求堆积

导出到 Prometheus 会生成下面几组时序:

text 复制代码
http_server_requests_active_seconds_active_tasks  1
http_server_requests_active_seconds_duration_sum 0.0024552
http_server_requests_active_seconds_max 0.002476

2.2 自定义指标名称

你可以通过配置 management.observations.http.server.requests.name 属性来自定义该指标名称。

示例:

yml 复制代码
management:
  observations:
    http:
      server:
        requests:
          name: myapp.http.server.requests

配置完成后:

  1. http.server.requests → 变为 myapp.http.server.requests
  2. http.server.requests.active → 自动变为 myapp.http.server.requests.active
  3. Actuator 端点访问地址随之变化:
    • /actuator/metrics/myapp.http.server.requests
    • /actuator/metrics/myapp.http.server.requests.active

Prometheus 导出的指标名也同步变更:

text 复制代码
myapp_http_server_requests_seconds_count
myapp_http_server_requests_seconds_sum
myapp_http_server_requests_seconds_max

myapp_http_server_requests_active_seconds_active_tasks

2.3 追加自定义标签

2.3.1 方式 1:追加标签

想要在默认标签基础上追加自定义标签,可以注册一个 @Bean,继承 org.springframework.http.server.observation 包下的 DefaultServerRequestObservationConvention

代码示例:

java 复制代码
@Component
public class CustomAddTagServerObservationConvention extends DefaultServerRequestObservationConvention {

    @Override
    public Iterable<KeyValue> getLowCardinalityKeyValues(ServerRequestObservationContext context) {
        // 拿到默认全部标签
        Iterable<KeyValue> defaultKeyValues = super.getLowCardinalityKeyValues(context);

        Observation.ObservationView observation = context.getObservation();

        return () -> {
            var defaultIterator = defaultKeyValues.iterator();
            return new java.util.Iterator<>() {
                private boolean customTagAdded = false;

                @Override
                public boolean hasNext() {
                    return defaultIterator.hasNext() || !customTagAdded;
                }

                @Override
                public KeyValue next() {
                    if (defaultIterator.hasNext()) {
                        return defaultIterator.next();
                    }
                    if (!customTagAdded) {
                        customTagAdded = true;
                        // 追加自定义低基数标签,业务维度,例如环境、app、traceEnv
                        return KeyValue.of("app_env", "prod");
                    }
                    throw new java.util.NoSuchElementException();
                }
            };
        };
    }
}

效果:http.server.requests 指标标签 = 默认全套标签 + app_env=prod

2.3.2 方式 2:完全替换全部标签

想要完全替换默认标签,可以注册一个实现 ServerRequestObservationConvention 接口的 @Bean

代码示例:

java 复制代码
@Component
public class FullReplaceServerObservationConvention implements ServerRequestObservationConvention {

    @Override
    public String getName() {
        // 指标名称,优先级低于配置 management.observations.http.server.requests.name
        return "http.server.requests";
    }

    @Override
    public Iterable<KeyValue> getLowCardinalityKeyValues(ServerRequestObservationContext context) {
        // 完全自己构造标签集合,没有父类默认标签!
        return java.util.List.of(
                KeyValue.of("http_method", context.getCarrier().getMethod()),
                KeyValue.of("http_status", String.valueOf(context.getResponse().getStatus())),
                KeyValue.of("biz_app", "demo‑service")
        );
    }

    @Override
    public Iterable<KeyValue> getHighCardinalityKeyValues(ServerRequestObservationContext context) {
        // 高基数标签(一般放traceId,不做metrics聚合)
        return java.util.List.of();
    }
}

2.4 把已捕获异常埋入指标标签

部分场景中,Web 控制器内部已经 try‑catch 捕获并处理掉的异常,不会自动填充到 http.server.requestsexception 指标标签上。

应用可以手动开启该行为:把捕获到的异常存入 请求属性(request attribute)Observation 过滤器就会读取该属性,把异常写入指标标签。

需要设置请求属性:ServerRequestObservationContext.CURRENT_EXCEPTION_ATTRIBUTE

代码示例:

java 复制代码
@RestController
public class DemoController {

    @GetMapping("/demo")
    public String demo(HttpServletRequest request) {
        try {
            throw new RuntimeException("业务自定义异常");
        } catch (RuntimeException e) {
            // 关键:将捕获处理过的异常放入request属性,observation过滤器读取此属性
            request.setAttribute(ServerRequestObservationContext.CURRENT_EXCEPTION_ATTRIBUTE, e);
            return "业务降级返回";
        }
    }
}

2.5 自定义过滤:跳过部分请求不采集指标

默认采集全部 HTTP 请求。如果需要自定义请求过滤逻辑(跳过某些请求不采集指标),注册一个 FilterRegistrationBean<ServerHttpObservationFilter> 类型的 @Bean

ServerHttpObservationFilter 是生成 http.server.requests 的核心过滤器。

通过 FilterRegistrationBean 可以设置:过滤匹配模式、排除路径、顺序。

代码示例:

java 复制代码
@Configuration
public class ObservationFilterConfig {

    @Bean
    public FilterRegistrationBean<ServerHttpObservationFilter> observationFilterRegistration(ServerHttpObservationFilter filter) {
        FilterRegistrationBean<ServerHttpObservationFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(filter);
        // 只匹配 /api/**,其余路径不采集指标;也可以 setUrlPatterns、addUrlPatterns
        registration.addUrlPatterns("/api/*");
        // 设置过滤器顺序
        registration.setOrder(1);
        return registration;
    }
}

⚠️注意:不是实现 FilterRegistrationBean,是构造 FilterRegistrationBean<ServerHttpObservationFilter> 的Bean,设置它的注册参数。不要自己 newFilter

上面是白名单;如果要做黑名单(排除某些路径),上面这种 URL pattern 方式能力有限。

更灵活方案:自定义 ServerRequestObservationConvention,或者自定义ObservationPredicate,在 Observation 层面跳过观测。

java 复制代码
@Configuration
public class ObsPredicateConfig {
    @Bean
    public ObservationPredicate observationPredicate() {
        return (name, context) -> {
            // http.server.requests 并且路径以 /actuator 开头,则不生成观测
            if ("http.server.requests".equals(name) && context instanceof org.springframework.http.server.observation.ServerRequestObservationContext ctx) {
                String path = ctx.getCarrier().getRequestURI();
                return !path.startsWith("/actuator");
            }
            return true;
        };
    }
}

ObservationPredicate:全局开关,返回 false 代表不创建该Observation,完全不产生指标 ,比 Filter 粒度更精准。


2. Spring WebFlux 指标

Spring MVC 指标基本一致,就不赘述了!!!

自动配置会对所有由 Spring WebFlux 控制器、函数式处理器处理的请求做指标埋点。默认生成指标名称为 http.server.requests。你可以通过配置 management.observations.http.server.requests.name 属性来自定义该指标名称。

想要在默认标签基础上追加自定义标签,可以注册一个 @Bean,继承 org.springframework.http.server.reactive.observation 包下的 DefaultServerRequestObservationConvention

想要完全替换默认标签,可以注册一个实现 ServerRequestObservationConvention 接口的 @Bean

部分场景下,控制器与函数式处理器内部捕获处理过的异常,不会作为请求指标的标签被记录。应用可选择开启该能力:将已处理的异常设置为请求属性,即可把异常记录进指标。

相关推荐
liudashuang20171 小时前
Kafka Producer 隐藏深坑:Sender 线程自阻塞(自死锁)导致 BufferExhaustedException 完整复盘
java·分布式·kafka·linq
风筱1 小时前
Idea的CC GUI插件安装Claude Code SDK失败
java·ide·ai编程
m0_527034331 小时前
异步任务审核系统设计:消息队列、超时重试与失败补偿
java·大数据·开发语言
xbgRS1 小时前
springBoot项目配置加载优先级
java·spring boot
zzzll11112 小时前
Loop Engineering:循环工程的原理、实践与应用
java·数据库·python
假客套2 小时前
记一次若依 Excel 导出踩坑:Permission denied、401 报错完整排查记录
java·若依·linux服务器
岁岁养乐多2 小时前
深入解析 Spring @Cacheable 注解:从声明式缓存 到多维替代方案
java
开发者联盟league2 小时前
maven核心插件介绍
java·maven
代码方舟2 小时前
Java数据工程:利用天远车辆vin码查车辆信息详版优化抵押贷款合规体验
java·人工智能