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. 如何自定义 HealthIndicator、MeterBinder 和业务指标。
  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

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

依赖和基础配置 ​

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 不能乱用?如果把 userId、orderNo、patientId 放进 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-actuator 和 micrometer-registry-prometheus,开放 /actuator/prometheus 端点,Prometheus 按配置定时拉取指标并存储为时间序列,Grafana 再基于 Prometheus 数据展示看板和告警。

如何自定义业务指标?
使用 Micrometer 的 MeterRegistry 注册 Counter、Timer、Gauge 等指标。例如采集平台可以记录采集成功数、失败数、队列长度、医院接口耗时。指标 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 决定能不能快速定位问题。真正的生产级项目,不是接口能跑就结束,而是出问题时能被看见、能被定位、能被平台安全地处理。