Spring Boot Actuator 监控端点
字节跳动P6面试间,面试官翻到简历上"有生产环境运维经验"这一行,问:
"你们生产环境的 Spring Boot 应用,怎么做监控的?"
候选人小钱说:"用 Prometheus 采集指标,Grafana 做可视化。"面试官追问:"Spring Boot 端点怎么暴露的?"小钱说:"引入 actuator 依赖,然后配置一下。"
面试官追问:"/actuator/health 和 /actuator/health/liveness 有什么区别?"小钱愣住了。面试官又问:"怎么防止 actuator 端点被未授权访问?"小钱答不上来。
【面试官心理】
这道题我用来测试候选人的生产运维意识。能说出常用端点名称的占 60%,能说出健康检查配置的占 30%,能讲清楚安全防护和外部集成的只有 10%。现在面试越来越注重生产经验,只会说"引入依赖配一下"的人很容易露馅。
一、Actuator 核心端点 🔴
1.1 必须掌握的端点
Spring Boot Actuator 提供了大量内置端点,以下是面试中最常被问到的:
1.2 引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Actuator 默认只暴露 health 和 info 两个端点。其他端点需要显式配置暴露:
management:
endpoints:
web:
exposure:
include: health,info,beans,conditions,env,metrics,loggers
exclude: heapdump,threaddump # 排除敏感端点
base-path: /actuator # 端点前缀,默认是 /actuator
二、health 端点深度解析 🟡
2.1 health 端点的细节层级
Spring Boot 2.3+ 对 health 端点做了重大拆分:
# application.yml
management:
endpoint:
health:
show-details: always # always | when-authorized | never
probes:
enabled: true # 启用存活探针和就绪探针
拆分后的健康检查:
/actuator/health/liveness:存活探针(Kubernetes liveness probe)
- 如果返回 DOWN,说明应用处于死锁状态,需要重启
/actuator/health/readiness:就绪探针(Kubernetes readiness probe)
- 如果返回 DOWN,说明应用还没准备好接收流量(比如数据库连接失败)
/actuator/health:聚合健康状态
// GET /actuator/health
{
"status": "UP",
"components": {
"db": {
"status": "UP",
"details": {
"database": "MySQL",
"validationQuery": "isValid()"
}
},
"redis": {
"status": "DOWN",
"details": {
"error": "redis.clients.jedis.exceptions.JedisConnectionException"
}
},
"diskSpace": {
"status": "UP"
}
}
}
⚠️
show-details 默认是 when-authorized,意味着只有认证用户才能看到详细信息。在开发/测试环境建议设为 always,生产环境保持 when-authorized 或者 never。
2.2 自定义健康检查
@Component
public class CustomHealthIndicator implements HealthIndicator {
@Override
public Health health() {
try {
// 检查自定义业务逻辑
boolean healthy = checkBusinessHealth();
if (healthy) {
return Health.up()
.withDetail("responseTime", 100)
.withDetail("activeConnections", 5)
.build();
} else {
return Health.down()
.withDetail("error", "Service unavailable")
.build();
}
} catch (Exception e) {
return Health.down()
.withDetail("error", e.getMessage())
.build();
}
}
}
三、@Endpoint 注解体系 🟡
3.1 自定义端点
Spring Boot 允许自定义 Actuator 端点:
@Endpoint(id = "custom")
public class CustomEndpoint {
@ReadOperation
public Map<String, Object> getCustomInfo() {
Map<String, Object> info = new HashMap<>();
info.put("customData", "some value");
info.put("timestamp", System.currentTimeMillis());
return info;
}
@WriteOperation
public String triggerAction(@Selector String action) {
return "Triggered: " + action;
}
@DeleteOperation
public String clearCache(@Selector String cacheName) {
return "Cleared: " + cacheName;
}
}
management:
endpoints:
web:
exposure:
include: custom
endpoint:
custom:
enabled: true
💡
自定义端点时,默认情况下所有操作都不需要认证。如果你的端点涉及敏感操作,需要配合 Spring Security 进行权限控制。
四、安全防护 🟡
4.1 禁止未授权访问
Actuator 端点如果暴露到公网,可能造成严重的信息泄露。以下是必须做的安全配置:
management:
endpoints:
web:
exposure:
include: health,info,metrics
exclude: env,beans,conditions,configprops,heapdump,threaddump
endpoint:
health:
show-details: when-authorized # 只给授权用户看详情
spring:
security:
endpoints:
web:
exposure:
include: health
authorization:
endpoints:
health:
access:
- hasRole('ADMIN') # 只有 ADMIN 角色能访问健康详情
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
// actuator 端点需要认证
.requestMatchers("/actuator/**").authenticated()
.anyRequest().permitAll()
)
.httpBasic(); // 使用 HTTP Basic 认证
return http.build();
}
}
⚠️
生产环境绝对不能把 heapdump、threaddump、env 这些端点直接暴露出去。heapdump 可以下载完整的堆内存快照,里面包含所有对象和字符串(可能包含密码、Token 等敏感信息),threaddump 可以看到方法调用栈(可能泄露业务逻辑)。
五、与 Prometheus/Grafana 集成 🟢
5.1 暴露 Prometheus 端点
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
management:
endpoints:
web:
exposure:
include: health,prometheus,metrics
metrics:
tags:
application: ${spring.application.name}
# GET /actuator/prometheus
# TYPE jvm_memory_used_bytes gauge
jvm_memory_used_bytes{area="heap",id="Eden Space",application="my-app"} 1.23E8
5.2 Grafana Dashboard 配置
{
"dashboard": {
"panels": [
{
"title": "JVM Memory",
"type": "graph",
"targets": [
{
"expr": "jvm_memory_used_bytes{application=\"my-app\", area=\"heap\"}",
"legendFormat": "{{id}}"
}
]
},
{
"title": "HTTP Requests",
"type": "graph",
"targets": [
{
"expr": "http_server_requests_seconds_count{application=\"my-app\"}",
"legendFormat": "{{uri}} - {{status}}"
}
]
}
]
}
}
六、常用排查端点 🟢
6.1 beans 端点
# 查看所有 Bean,包括 Bean 的依赖关系
GET /actuator/beans
{
"contexts": {
"application": {
"beans": {
"dataSource": {
"aliases": [],
"scope": "singleton",
"type": "com.zaxxer.hikari.HikariDataSource",
"resource": "class path resource [application.yml]",
"dependencies": ["dataSourceInitializer"]
}
}
}
}
}
6.2 env 端点
# 查看所有配置属性,包括从环境变量注入的值
GET /actuator/env
GET /actuator/env/spring.datasource.password # 查看特定属性
POST /actuator/env # 修改运行时属性
{
"name": "server.tomcat.connection-timeout",
"value": 5000
}
6.3 loggers 端点
# 查看和修改日志级别(运行时生效)
GET /actuator/loggers
POST /actuator/loggers/com.example.service
{
"configuredLevel": "DEBUG"
}
七、面试标准回答
7.1 P5 级别
"Spring Boot Actuator 提供了很多监控端点,比如 /actuator/health 做健康检查、/actuator/metrics 查看指标、/actuator/beans 查看 Bean 列表。使用时引入 spring-boot-starter-actuator 依赖,然后通过 management.endpoints.web.exposure.include 配置暴露哪些端点。"
7.2 P6 级别
"Actuator 默认只暴露 health 和 info,其他端点需要配置暴露。health 端点在 Spring Boot 2.3+ 拆分为 liveness 和 readiness 两个探针,分别用于 Kubernetes 的存活检测和就绪检测。
自定义端点使用 @Endpoint 注解,配合 @ReadOperation/@WriteOperation/@DeleteOperation 定义操作。安全方面,heapdump、threaddump、env 等敏感端点必须在生产环境禁止暴露或加上认证。show-details 默认是 when-authorized,只有认证用户才能看详情。"
7.3 P7 级别
"Actuator 是 Spring Boot 生产运维的核心。我之前在项目中把 Actuator 和 Prometheus 做了深度集成——通过 micrometer-registry-prometheus 暴露 /actuator/prometheus 端点,Grafana 配置了 JVM 监控、Datasource 连接池监控、自定义业务指标监控。
踩过一个坑:最开始我们把所有端点都暴露了,结果压测时被攻击者扫描到了 /actuator/heapdump 端点,直接 dump 了生产环境的堆内存快照。后来我们做了三层防护:1. 禁止暴露敏感端点;2. actuator 端点加 HTTP Basic 认证;3. 在网关层做了 IP 白名单。"
【面试官心理】
P7 的回答重点在于"生产踩坑"和"系统建设"。能说出安全防护细节和监控集成的候选人,说明他真正在生产环境用过这些工具,而不只是看过文档。