Skip to content

Spring Boot Actuator

Spring Boot Actuator 是 Spring Boot 提供的生产可观测能力入口。它把应用内部的健康状态、指标、线程、环境配置、日志级别、自动配置条件等信息,通过标准端点暴露给开发、运维、监控系统和容器平台。

零基础先记住一句话:

Actuator 不是“多几个 URL”,而是让应用能被探活、被监控、被诊断、被平台治理。

如果没有 Actuator,线上系统经常只能靠“进程还在不在”“日志有没有报错”来猜状态。真实生产里,进程活着不代表服务可用:数据库可能断了,Redis 可能超时,线程池可能满了,下游接口可能不可用,自动配置可能没有生效。

学习目标

学完本章你要能回答:

  1. Actuator 解决什么问题,和普通业务接口有什么区别。
  2. Health、Liveness、Readiness 分别表示什么。
  3. K8s 为什么不能只用进程存活判断服务可用。
  4. /metrics/prometheus、Micrometer、Prometheus、Grafana 的关系。
  5. 如何自定义 HealthIndicatorMeterBinder 和业务指标。
  6. /conditions/env/configprops/threaddump 怎么用于排查。
  7. 为什么不能把所有 Actuator 端点暴露到公网。
  8. 医疗数据采集平台和订单系统中 Actuator 怎么落地。

为什么需要 Actuator

线上应用有三类问题,单靠日志很难快速判断。

问题例子没有 Actuator 会怎样
实例是否能接流量应用启动了,但数据库连接池还没准备好网关或 K8s 可能把流量打进异常实例
系统是否正在变慢接口 P95 升高、线程池队列堆积只能等用户反馈或翻大量日志
配置和自动配置是否正确某个 Starter 没生效、Profile 错了排查靠猜,难以定位条件不匹配

Actuator 的作用是把这些状态标准化地暴露出来:

mermaid
flowchart TD
    A["Spring Boot 应用"] --> B["Actuator 端点"]
    B --> C["K8s 探针"]
    B --> D["Prometheus 指标采集"]
    B --> E["开发排查"]
    B --> F["运维平台"]
    C --> G["决定是否接流量或重启"]
    D --> H["Grafana 看板和告警"]
    E --> I["定位配置、线程、Bean、条件"]

它不是替代日志,而是补齐日志不擅长的维度:

能力日志Actuator / 指标
单次请求细节
整体趋势
实例健康需要分析标准端点直接返回
自动配置条件日志不直观/conditions
线程快照需要进机器/threaddump
日志级别调整要改配置或重启/loggers 可动态调整

Actuator 整体链路

生产监控通常是这条链路:

mermaid
flowchart TD
    A["业务代码"] --> B["Micrometer 记录指标"]
    B --> C["Actuator 暴露 metrics/prometheus"]
    C --> D["Prometheus 定时拉取"]
    D --> E["Prometheus 存储时间序列"]
    E --> F["Grafana 展示看板"]
    E --> G["Alertmanager 告警"]

健康检查通常是这条链路:

mermaid
flowchart TD
    A["K8s 或网关"] --> B["访问 /actuator/health/readiness"]
    B --> C{"应用是否准备好"}
    C -- "是" --> D["继续转发流量"]
    C -- "否" --> E["从流量池摘除"]
    A --> F["访问 /actuator/health/liveness"]
    F --> G{"进程是否仍可恢复"}
    G -- "是" --> H["保持运行"]
    G -- "否" --> I["重启容器"]

这两个链路解决的问题不同:指标用于观察趋势和告警,健康检查用于平台控制流量和生命周期。

常见端点

端点作用生产建议
/actuator/health应用健康状态可以暴露给探针,但细节要控制
/actuator/health/liveness存活状态给 K8s livenessProbe
/actuator/health/readiness就绪状态给 K8s readinessProbe
/actuator/metrics指标入口内网或受控访问
/actuator/prometheusPrometheus 格式指标给 Prometheus 拉取
/actuator/info应用信息可放版本、构建号,避免敏感信息
/actuator/envEnvironment 配置源和值敏感,必须鉴权
/actuator/configprops配置绑定结果敏感,必须鉴权
/actuator/beansBean 列表敏感,生产慎开
/actuator/conditions自动配置条件报告排查自动配置很有用,生产慎开
/actuator/threaddump线程栈排查卡顿,必须鉴权
/actuator/heapdump堆转储极敏感,通常不对 Web 暴露
/actuator/loggers查看和调整日志级别内网受控使用

最常见的生产暴露组合:

yaml
management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus

排查阶段可以临时开放 conditionsenvconfigpropsthreaddump,但必须有权限控制,排查后及时关闭。

依赖和基础配置

Maven 依赖:

xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

基础配置:

yaml
management:
  server:
    port: 9090
  endpoints:
    web:
      base-path: /actuator
      exposure:
        include: health,info,metrics,prometheus
  endpoint:
    health:
      probes:
        enabled: true
      show-details: never

为什么建议管理端口和业务端口分离?

  1. 业务网关可以只转发 8080,不暴露 9090。
  2. 运维和监控系统走内网访问管理端口。
  3. 安全策略更清楚。
  4. 业务接口异常时,管理端口仍可能提供诊断能力。

验证:

bash
curl http://localhost:9090/actuator/health
curl http://localhost:9090/actuator/prometheus

Health、Liveness、Readiness

很多人只知道 /health,但生产里更重要的是区分存活和就绪。

状态含义平台动作
Liveness进程是否还活着,是否需要重启失败时 K8s 重启容器
Readiness应用是否准备好接收流量失败时 K8s 摘除流量
Health综合健康状态给人或平台看整体状态

为什么不能混用?

假设应用启动了,但数据库暂时连接不上:

  1. Liveness 可以仍然是 UP,因为进程没有死,稍后可能恢复。
  2. Readiness 应该是 DOWN,因为此时不能接业务流量。
  3. 如果把数据库失败放进 Liveness,K8s 会不断重启容器,可能让问题更严重。
mermaid
flowchart TD
    A["应用进程启动"] --> B["Liveness UP"]
    B --> C["初始化数据源、Redis、MQ"]
    C --> D{"核心依赖可用吗"}
    D -- "否" --> E["Readiness DOWN<br/>不接流量"]
    D -- "是" --> F["Readiness UP<br/>接收流量"]

Kubernetes 探针示例:

yaml
readinessProbe:
  httpGet:
    path: /actuator/health/readiness
    port: 9090
  initialDelaySeconds: 20
  periodSeconds: 10
  timeoutSeconds: 2

livenessProbe:
  httpGet:
    path: /actuator/health/liveness
    port: 9090
  initialDelaySeconds: 60
  periodSeconds: 20
  timeoutSeconds: 2

参数说明:

参数说明配错后果
initialDelaySeconds容器启动后多久开始探测太短会在应用未启动完成时误杀
periodSeconds探测频率太频繁会增加压力
timeoutSeconds探测超时太短可能误判,太长会拖慢摘流

自定义 HealthIndicator

健康检查适合检查核心依赖是否可用,例如数据库、Redis、MQ、医院接口、采集通道。

医疗采集平台示例:检查医院接口是否能快速探活。

java
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;

@Component
public class HospitalApiHealthIndicator implements HealthIndicator {

    private final HospitalApiClient hospitalApiClient;

    public HospitalApiHealthIndicator(HospitalApiClient hospitalApiClient) {
        this.hospitalApiClient = hospitalApiClient;
    }

    @Override
    public Health health() {
        try {
            boolean ok = hospitalApiClient.ping(1000);
            if (ok) {
                return Health.up()
                        .withDetail("hospitalApi", "reachable")
                        .build();
            }
            return Health.down()
                    .withDetail("hospitalApi", "unreachable")
                    .build();
        } catch (Exception ex) {
            return Health.down()
                    .withDetail("hospitalApi", "timeout")
                    .build();
        }
    }
}

客户端 Demo:

java
import org.springframework.stereotype.Component;

@Component
public class HospitalApiClient {

    public boolean ping(int timeoutMs) {
        // Demo:真实项目这里调用医院网关的轻量探活接口,并设置短超时。
        return timeoutMs > 0;
    }
}

健康检查原则:

原则原因
必须轻量探针会频繁访问,不能拖垮服务
必须有超时下游卡死时不能把 health 也卡死
不查大表健康检查不是业务报表
不泄露敏感信息不能把账号、连接串、内部 IP 暴露出去
区分核心和非核心依赖非核心依赖失败不一定要摘流

错误示例:

java
// 不推荐:健康检查里查询大量业务数据
select * from collect_result where collect_time > now() - interval 1 day;

健康检查应该回答“依赖是否可达、服务是否可用”,不应该做大范围业务查询。

Micrometer 指标体系

Spring Boot Actuator 的指标底层通常由 Micrometer 统一抽象。Micrometer 可以把同一套指标输出给 Prometheus、Graphite、Datadog 等系统。

核心关系:

mermaid
flowchart TD
    A["业务代码"] --> B["MeterRegistry"]
    B --> C["Counter / Timer / Gauge"]
    C --> D["Actuator metrics"]
    C --> E["Prometheus registry"]
    E --> F["/actuator/prometheus"]

常见指标类型:

类型说明示例
Counter只增不减的计数请求数、采集成功数、失败数
Gauge可上下变化的瞬时值队列长度、在线连接数
Timer记录耗时和次数接口耗时、下游调用耗时
DistributionSummary记录分布消息大小、批次大小

Counter Demo

java
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.stereotype.Component;

@Component
public class CollectMetrics {

    private final Counter successCounter;
    private final Counter failedCounter;

    public CollectMetrics(MeterRegistry registry) {
        this.successCounter = Counter.builder("collect_task_success_total")
                .description("采集任务成功总数")
                .tag("system", "hospital")
                .register(registry);
        this.failedCounter = Counter.builder("collect_task_failed_total")
                .description("采集任务失败总数")
                .tag("system", "hospital")
                .register(registry);
    }

    public void success() {
        successCounter.increment();
    }

    public void failed() {
        failedCounter.increment();
    }
}

Timer Demo

java
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.springframework.stereotype.Component;

import java.time.Duration;

@Component
public class HospitalApiMetrics {

    private final Timer requestTimer;

    public HospitalApiMetrics(MeterRegistry registry) {
        this.requestTimer = Timer.builder("hospital_api_request_duration")
                .description("医院接口调用耗时")
                .publishPercentiles(0.5, 0.95, 0.99)
                .maximumExpectedValue(Duration.ofSeconds(10))
                .register(registry);
    }

    public <T> T record(java.util.function.Supplier<T> supplier) {
        return requestTimer.record(supplier);
    }
}

使用:

java
String result = hospitalApiMetrics.record(() -> hospitalApiClient.fetch("/patients"));

Gauge Demo

java
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.stereotype.Component;

import java.util.concurrent.BlockingQueue;

@Component
public class QueueMetrics {

    public QueueMetrics(MeterRegistry registry, BlockingQueue<Runnable> collectQueue) {
        Gauge.builder("collect_queue_size", collectQueue, BlockingQueue::size)
                .description("采集任务队列长度")
                .register(registry);
    }
}

指标命名建议:

  1. 使用业务语义明确的名称。
  2. 计数器通常以 _total 结尾。
  3. tag 不要放高基数字段,例如用户 ID、订单号、患者 ID。
  4. 指标要能驱动告警或排查,不要为了好看乱加。

为什么 tag 不能乱用?如果把 userIdorderNopatientId 放进 tag,每个不同值都会生成一组时间序列,Prometheus 压力会急剧上升。

Prometheus 和 Grafana 怎么配合

Prometheus 拉取配置示例:

yaml
scrape_configs:
  - job_name: "spring-boot-app"
    metrics_path: "/actuator/prometheus"
    static_configs:
      - targets: ["app-1:9090", "app-2:9090"]

Grafana 看板常见指标:

指标说明
http_server_requests_seconds_countHTTP 请求次数
http_server_requests_seconds_maxHTTP 最大耗时
jvm_memory_used_bytesJVM 内存使用
jvm_gc_pause_seconds_countGC 次数
hikaricp_connections_activeHikari 活跃连接
system_cpu_usageCPU 使用
自定义业务指标采集成功率、订单失败数、队列长度

一个基础告警思路:

告警判断
实例不可用readiness 连续失败
接口慢P95 超过阈值持续 5 分钟
错误率高5xx 比例超过阈值
连接池紧张活跃连接接近最大连接数
采集积压队列长度持续增长
下游不稳定医院接口 Timer P95 升高、失败 Counter 增长

排查自动配置:conditions

/actuator/conditions 是排查自动配置最重要的端点之一。

典型场景:你引入了一个自定义 Starter,但默认 Bean 没出来。

排查流程:

mermaid
flowchart TD
    A["默认 Bean 没创建"] --> B["访问 /actuator/conditions"]
    B --> C["搜索目标 AutoConfiguration"]
    C --> D{"是否出现在报告里"}
    D -- "否" --> E["检查 starter 依赖和 imports/spring.factories"]
    D -- "是" --> F{"Positive 还是 Negative"}
    F -- "Negative" --> G["看缺少 class、property、bean 还是 web 条件"]
    F -- "Positive" --> H["继续看是否 MissingBean 让位或 Bean 创建失败"]

conditions 能回答:

  1. 自动配置类有没有被发现。
  2. 条件为什么匹配。
  3. 条件为什么不匹配。
  4. 是否被排除。

它不能直接回答所有问题。例如 Bean 构造方法异常、配置绑定失败,还需要看日志和 /configprops

排查配置:env 和 configprops

/actuator/env

用于查看最终 Environment 中有哪些配置源和值。

适合排查:

  1. Profile 是否正确。
  2. 环境变量是否覆盖 yml。
  3. 命令行参数是否覆盖配置中心。
  4. 某个配置最终值是什么。

/actuator/configprops

用于查看 @ConfigurationProperties 的绑定结果。

适合排查:

  1. prefix 是否写错。
  2. 类型转换是否成功。
  3. 配置类是否注册。
  4. 默认值是否生效。

安全注意:这两个端点可能包含数据库地址、账号、密钥、Token。生产必须鉴权,并开启脱敏。

排查线程:threaddump

当接口卡死、CPU 高、请求积压时,可以看线程栈。

常见判断:

线程状态可能含义
RUNNABLE 很多CPU 计算、忙循环、序列化、压缩、加密
WAITING 很多等待队列、锁、连接、条件变量
BLOCKEDJava synchronized 锁竞争
大量 Tomcat 线程等待下游下游慢、连接池满、HTTP 客户端超时长
Hikari 获取连接等待数据库连接池耗尽

排查链路:

mermaid
flowchart TD
    A["接口大量超时"] --> B["看指标 P95 和错误率"]
    B --> C["看 threaddump"]
    C --> D{"线程卡在哪里"}
    D -- "数据库连接" --> E["查 Hikari 指标、慢 SQL、锁等待"]
    D -- "HTTP 下游" --> F["查下游耗时、超时、重试"]
    D -- "锁竞争" --> G["查 synchronized 或业务锁"]
    D -- "CPU RUNNABLE" --> H["查热点代码和 GC"]

动态调整日志级别

线上排查时,有时需要临时把某个包日志改成 DEBUG,但不想重启。

查看日志级别:

bash
curl http://localhost:9090/actuator/loggers/com.example.collect

修改日志级别:

bash
curl -X POST http://localhost:9090/actuator/loggers/com.example.collect \
  -H "Content-Type: application/json" \
  -d "{\"configuredLevel\":\"DEBUG\"}"

恢复:

bash
curl -X POST http://localhost:9090/actuator/loggers/com.example.collect \
  -H "Content-Type: application/json" \
  -d "{\"configuredLevel\":\"INFO\"}"

注意:

  1. 只能在受控内网使用。
  2. DEBUG 日志可能非常多,排查完要恢复。
  3. 不要把敏感数据打印出来。

商业场景一:医疗数据采集平台

医疗采集平台最常见的问题是:采集失败、医院接口慢、任务积压、下游不稳定、实例启动后还没准备好就接流量。

建议指标:

指标含义
collect_task_success_total采集成功数
collect_task_failed_total采集失败数
collect_queue_size采集队列长度
hospital_api_request_duration医院接口耗时
collect_retry_total重试次数
collect_dead_letter_total死信或最终失败数量

建议健康检查:

依赖是否影响 readiness原因
数据库无法读取任务和写结果
Redis看业务如果强依赖缓存或锁,则影响
MQ无法消费或投递采集任务
医院接口看场景单个医院失败不一定摘除整个服务
字典缓存字典未加载可能导致解析错误

采集服务启动过程:

mermaid
flowchart TD
    A["应用启动"] --> B["Liveness UP"]
    B --> C["加载配置和字典"]
    C --> D["初始化数据源和 MQ"]
    D --> E{"核心依赖是否就绪"}
    E -- "否" --> F["Readiness DOWN"]
    E -- "是" --> G["Readiness UP"]
    G --> H["开始接收采集任务"]

商业场景二:订单系统

订单系统关注的是:接口错误率、支付回调失败、库存扣减慢、数据库连接池、MQ 发送失败。

建议指标:

指标含义
order_create_total创建订单次数
order_create_failed_total创建订单失败数
pay_callback_total支付回调次数
pay_callback_duplicate_total重复回调次数
inventory_deduct_duration库存扣减耗时
mq_send_failed_total消息发送失败

订单系统告警不能只看实例健康。实例 UP 但订单失败率升高,也必须告警。

安全边界

Actuator 最大的风险是暴露了太多内部信息。

高风险端点:

端点风险
/env可能泄露配置、账号、Token
/configprops可能泄露绑定后的敏感配置
/beans暴露内部 Bean 和类结构
/heapdump可能包含用户数据、Token、密码
/threaddump可能暴露业务类名、SQL、调用链
/loggers被滥用可能打开大量日志

生产建议:

yaml
management:
  server:
    port: 9090
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus
  endpoint:
    health:
      show-details: never

配合:

  1. 管理端口只允许内网访问。
  2. 网关不要转发 Actuator 端点到公网。
  3. 敏感端点必须鉴权。
  4. 开启配置脱敏。
  5. 排查临时开放端点后要关闭。
  6. heapdump 更推荐通过安全运维通道获取,不建议 Web 暴露。

生产排查流程

接口变慢

mermaid
flowchart TD
    A["接口变慢"] --> B["看 http 指标 P95/P99"]
    B --> C["按 URI、状态码、实例分组"]
    C --> D{"是否单实例异常"}
    D -- "是" --> E["看该实例线程、GC、连接池"]
    D -- "否" --> F["看数据库、Redis、MQ、下游接口"]
    E --> G["threaddump / metrics"]
    F --> H["下游指标和慢 SQL"]

自动配置没生效

mermaid
flowchart TD
    A["Starter 默认 Bean 不存在"] --> B["看 /conditions"]
    B --> C["看自动配置类是否出现"]
    C --> D["看 Negative matches"]
    D --> E["检查依赖、配置、Profile、用户 Bean"]
    E --> F["看 /configprops 和日志"]

连接池耗尽

看指标:

  1. Hikari active connections。
  2. Hikari pending threads。
  3. HTTP 请求耗时。
  4. 慢 SQL。
  5. 线程栈是否卡在获取连接。

处理方向:

原因处理
慢 SQL 占连接优化 SQL、索引、事务
事务过长缩小事务边界
连接泄漏开启泄漏检测,检查未关闭资源
并发过高限流、队列、扩容
下游数据库慢降级、读写分离、排查数据库

常见坑

后果正确做法
所有端点都暴露敏感信息泄露只暴露必要端点
health 做重查询探针拖垮服务轻量检查并设置超时
liveness 检查数据库数据库短故障导致容器反复重启数据库通常影响 readiness,不一定影响 liveness
readiness 永远 UP未准备好就接流量依赖未就绪时返回 DOWN
指标 tag 放用户 ID时间序列爆炸tag 只放低基数字段
只看 health 不看业务指标业务失败但实例健康补充错误率、耗时、队列等指标
DEBUG 日志忘记恢复日志量暴涨、磁盘压力排查后恢复 INFO
prometheus 暴露公网指标和内部路径泄露内网访问和鉴权

面试标准回答

Actuator 是什么?
Actuator 是 Spring Boot 的生产可观测和运维端点体系,用来暴露健康检查、指标、环境、配置绑定、自动配置条件、线程栈、日志级别等信息。它让应用可以被 K8s 探活、被 Prometheus 采集、被开发排查,而不是只能靠进程和日志猜状态。

Liveness 和 Readiness 区别是什么?
Liveness 表示进程是否还活着,失败时平台通常重启容器;Readiness 表示应用是否准备好接流量,失败时平台应该摘除流量但不一定重启。数据库短暂不可用通常应该影响 Readiness,而不一定影响 Liveness,否则可能造成容器反复重启。

Actuator 怎么接入 Prometheus?
项目引入 spring-boot-starter-actuatormicrometer-registry-prometheus,开放 /actuator/prometheus 端点,Prometheus 按配置定时拉取指标并存储为时间序列,Grafana 再基于 Prometheus 数据展示看板和告警。

如何自定义业务指标?
使用 Micrometer 的 MeterRegistry 注册 CounterTimerGauge 等指标。例如采集平台可以记录采集成功数、失败数、队列长度、医院接口耗时。指标 tag 要控制基数,不能把用户 ID、订单号、患者 ID 这类高基数字段放进去。

Actuator 有什么安全风险?
/env/configprops/beans/heapdump/threaddump 等端点可能暴露配置、Token、类结构、内存数据和调用栈。生产环境应只暴露必要端点,管理端口走内网,敏感端点必须鉴权,健康检查细节不要对外暴露。

关联知识点

知识点说明
Spring Boot 从零到生产级掌握Spring Boot 主线
Spring Boot 扩展点HealthIndicator、MeterBinder、FailureAnalyzer 所在扩展点体系
自动配置原理conditions 排查自动配置
配置体系env 和 configprops 排查配置
启动流程readiness、Runner、启动阶段
Spring Boot 面试标准回答与追问
JVM 排查工具线程、堆、GC 排查
生产监控与线上问题排查日志、指标、Trace联动及CPU、OOM、线程池、连接池、容器故障Runbook
Spring Boot Admin将多个应用的Actuator端点集中展示和管理

本章小结

Actuator 的核心价值是让 Spring Boot 应用进入“可观测、可探活、可排查、可治理”的生产状态。健康检查决定实例能不能接流量,指标决定能不能提前发现趋势,conditions/env/configprops/threaddump 决定能不能快速定位问题。真正的生产级项目,不是接口能跑就结束,而是出问题时能被看见、能被定位、能被平台安全地处理。