1、概览 {#1概览}
本文将带你了解 Spring Boot Actuator,以及如何在 Spring Boot 和 WebFlux 中使用、配置和扩展这个监控工具,充分利用响应式编程模型。
2、Actuator 是啥? {#2actuator-是啥}
从本质上讲,Actuator 为应用带来了生产就绪的功能。
有了 Actuator 后,监控应用程序、收集指标、了解流量或数据库状态就变得易如反掌。
这个库的主要好处是,可以获得生产级工具,而无需自己实际实现这些功能。
Actuator 主要公开应用的运行信息 - 健康状况、指标、信息、转储(dump)、环境等。它使用 HTTP 端点或 JMX Bean 与客户端进行交互。
一旦在 classpath 中添加了该依赖,多个端点就已经开箱即用。与大多数 Spring 模块一样,可以通过多种方式轻松配置或扩展它。
3、入门 {#3入门}
首先,在 Spring Boot 项目中添加 spring-boot-actuator
依赖,以启用 Spring Boot Actuator。
Mave:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
该依赖的版本号已经在 spring-boot-starter-parent
中声明了,所以只要你继承了 Parent 项目,不需要手动声明版本号。
Actuator 与技术无关,Actuator 将其模型定义为可插拔和可扩展的,而不依赖 MVC。因此,可以利用 MVC 和 WebFlux 作为底层 Web 实现,还可以通过实现正确的适配器来添加新的实现。也支持 JMX,无需任何额外代码即可暴露端点。
4、端点配置 {#4端点配置}
4.2、默认端点和安全配置 {#42默认端点和安全配置}
Actuator 禁用了大部分端点。因此,默认情况下只有 /health
和 /info
这两个端点可用。
如果想启用所有端点,可以设置 management.endpoints.web.exposure.include=*
。或者,也可以列出应启用的端点。
另外,Actuator 与常规应用 Security 规则共享 Security 配置,从而大大简化了 Security 模型。因此,如果项目中使用了 Spring Security,就必须调整 Actuator 的 Security 规则,以允许 Actuator 端点。
只需添加一个 /actuator/**
条目即可:
@Bean
public SecurityWebFilterChain securityWebFilterChain(
ServerHttpSecurity http) {
return http.authorizeExchange()
.pathMatchers("/actuator/**").permitAll()
.anyExchange().authenticated()
.and().build();
}
所有 Actuator 端点都默认位于 /actuator
路径下。也可以使用配置属性 management.endpoints.web.base-path
来调整路径。
你可以在 Actuator 中文文档 中找到更多细节,
4.3、预定义的端点 {#43预定义的端点}
Actuator 部分预定义的端点如下:
/auditevents
列出了与安全审计相关的事件,如用户登录/注销。此外,还可以根据 Principal 或类型等字段进行过滤。/beans
返回BeanFactory
中所有可用的 Bean。与/auditevents
不同,它不支持过滤。/conditions
(之前称为/autoconfig
)会生成有关自动配置条件的报告。/configprops
允许获取所有@ConfigurationProperties
Bean。/env
返回当前环境属性(Environment Properties),也可以检索单个属性。/flyway
提供了有关 Flyway 数据库迁移的详细信息。/health
汇总了应用的健康状况。/heapdump
会构建并返回应用所用 JVM 的 Heap Dump。/info
返回一般信息。它可能是自定义数据、构建信息或最新提交的详细信息。/liquibase
的行为类似于/flyway
,但针对的是 Liquibase。/logfile
返回普通应用日志。/loggers
能够查询和修改应用的日志级别。/metrics
详细介绍了应用的指标。这可能包括通用指标和自定义指标。/prometheus
返回的指标与前一个类似,但格式化后可与 Prometheus 服务器一起使用。/scheduledtasks
提供了应用中每个计划(定时)任务的详细信息。/sessions
列出了 HTTP Session,前提是正在使用 Spring Session。/shutdown
可以优雅地关闭应用。/threaddump
会 dump 底层 JVM 的线程信息。
4.4、Actuator 端点的 Hypermedia {#44actuator-端点的-hypermedia}
Spring Boot 添加了一个发现端点,可返回所有可用 Actuator 端点的链接。这有助于发现 Actuator 端点及其相应的 URL。
默认情况下,可通过 /actuator
端点访问该发现端点,向这个 URL 发送 GET 请求,它就会返回各个端点的 Actuator 链接:
{
"_links": {
"self": {
"href": "http://localhost:8080/actuator",
"templated": false
},
"features-arg0": {
"href": "http://localhost:8080/actuator/features/{arg0}",
"templated": true
},
"features": {
"href": "http://localhost:8080/actuator/features",
"templated": false
},
"beans": {
"href": "http://localhost:8080/actuator/beans",
"templated": false
},
"caches-cache": {
"href": "http://localhost:8080/actuator/caches/{cache}",
"templated": true
},
// 省略其他的 ...
}
如上所示,/actuator
端点会在 _links
字段下返回所有可用的 Actuator 端点。
如果配置了自定义 Management Base Path,则应使用该基本路径作为发现 URL。例如,如果将 management.endpoints.web.base-path
设置为 /mgmt
,那么就应该请求 /mgmt
端点来查看链接列表。
注意,当 Management Base Path 设置为 /
时,发现端点会被禁用,以防止与其他映射发生冲突。
4.5、健康指标 {#45健康指标}
可以通过实现 HealthIndicator
接口来轻加自定义指标。ReactiveHealthIndicator
用于实现响应式健康检查。
自定义响应式健康检查:
@Component
public class DownstreamServiceHealthIndicator implements ReactiveHealthIndicator {
@Override
public Mono<Health> health() {
return checkDownstreamServiceHealth().onErrorResume(
ex -> Mono.just(new Health.Builder().down(ex).build())
);
}
private Mono<Health> checkDownstreamServiceHealth() {
// 可以使用 WebClient 来被动地检查健康状况
return Mono.just(new Health.Builder().up().build());
}
}
健康指标的一个方便之处在于,可以将其作为层次结构的一部分进行汇总。
因此,按照前面的例子,可以将所有下游服务归入 downstream-services
类别。只要每个嵌套的服务都是可访问的,那么这个类别就是健康的。
4.6、监控指标分组 {#46监控指标分组}
可以将健康指标组织成 组(Group),并对所有组员应用相同的配置。
例如,可以在 application.properties
中添加以下内容,创建一个名为 custom
的健康组:
management.endpoint.health.group.custom.include=diskSpace,ping
这样,custom
组就包含了 diskSpace
和 ping
健康指标。
现在,如果调用 /actuator/health
端点,它就会在 JSON 响应中返回新的健康组:
{"status":"UP","groups":["custom"]}
通过健康组,可以看到一些健康指标的综合结果。
在这种情况下,向 /actuator/health/custom
发送请求,响应如下:
{"status":"UP"}
可以通过 application.properties
配置组以显示更多细节:
management.endpoint.health.group.custom.show-components=always
management.endpoint.health.group.custom.show-details=always
现在,如果向 /actuator/health/custom
发起相同的请求,就能看到更多细节:
{
"status": "UP",
"components": {
"diskSpace": {
"status": "UP",
"details": {
"total": 499963170816,
"free": 91300069376,
"threshold": 10485760
}
},
"ping": {
"status": "UP"
}
}
}
也可以只向授权用户显示这些详细信息:
management.endpoint.health.group.custom.show-components=when_authorized
management.endpoint.health.group.custom.show-details=when_authorized
还可以自定义状态映射。
例如,它可以返回 207 状态码,而不是 HTTP 200 OK 响应:
management.endpoint.health.group.custom.status.http-mapping.up=207
上述配置告诉 Spring Boot,如果 custom
组状态为 UP
,则返回 207 HTTP 状态码。
4.7、指标 {#47指标}
从 Spring Boot 2 开始,内部度量标准已被 Micrometer 支持所取代,我们需要直接与 Micrometer 进行交互。Spring Boot 会自动配置一个类型为 MeterRegistry
的 Bean。
由于 Micrometer
现在是 Actuator 依赖的一部分,所以只要 Actuator 依赖在 classpath 中,就可以使用了。
从 /metrics
端点获取响应:
{
"names": [
"jvm.gc.pause",
"jvm.buffer.memory.used",
"jvm.memory.used",
"jvm.buffer.count",
// ...
]
}
获取特定指标的实际值,例如 /actuator/metrics/jvm.gc.pause
:
{
"name": "jvm.gc.pause",
"measurements": [
{
"statistic": "Count",
"value": 3.0
},
{
"statistic": "TotalTime",
"value": 7.9E7
},
{
"statistic": "Max",
"value": 7.9E7
}
],
"availableTags": [
{
"tag": "cause",
"values": [
"Metadata GC Threshold",
"Allocation Failure"
]
},
{
"tag": "action",
"values": [
"end of minor GC",
"end of major GC"
]
}
]
}
4.8、自定义 /info
端点 {#48自定义-info-端点}
可以使用 git-commit-id-plugin
依赖添加 git 详细信息。
<dependency>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
</dependency>
同样,也可以使用 Maven 或 Gradle 插件,在其中加入构建信息,包括名称、Group 和版本:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
4.9、创建自定义端点 {#49创建自定义端点}
创建一个 Actuator 端点,用于在应用中查询、启用和禁用 Feature:
@Component
@Endpoint(id = "features")
public class FeaturesEndpoint {
private Map<String, Feature> features = new ConcurrentHashMap<>();
@ReadOperation
public Map<String, Feature> features() {
return features;
}
@ReadOperation
public Feature feature(@Selector String name) {
return features.get(name);
}
@WriteOperation
public void configureFeature(@Selector String name, Feature feature) {
features.put(name, feature);
}
@DeleteOperation
public void deleteFeature(@Selector String name) {
features.remove(name);
}
public static class Feature {
private Boolean enabled;
// get / set 方法
}
}
要获得端点,需要一个 Bean。在本例中,使用 @Component
来实现这一点。此外,还需要用 @Endpoint
来装饰这个 Bean。
端点的路径由 @Endpoint
的 id
参数决定。在本例中,它会将请求路由到 /actuator/features
。
准备就绪后,就可以开始定义操作了:
@ReadOperation
:映射到 HTTPGET
@WriteOperation
:映射到 HTTPPOST
@DeleteOperation
:映射到 HTTPDELETE
Spring Boot 会在运行时注册该端点。
可以在日志中查看到:
[...].WebFluxEndpointHandlerMapping: Mapped "{[/actuator/features/{name}],
methods=[GET],
produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
[...].WebFluxEndpointHandlerMapping : Mapped "{[/actuator/features],
methods=[GET],
produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
[...].WebFluxEndpointHandlerMapping : Mapped "{[/actuator/features/{name}],
methods=[POST],
consumes=[application/vnd.spring-boot.actuator.v2+json || application/json]}"
[...].WebFluxEndpointHandlerMapping : Mapped "{[/actuator/features/{name}],
methods=[DELETE]}"[...]
在上述的日志中,可以看到 WebFlux 是如何暴露新端点的。如果切换到 MVC,也无需更改任何代码。
此外,这还有一些注意事项:
- 与 MVC 没有依赖
- 使用
@Endpoint(id = "features", enableByDefault = false)
启用或禁用端点。 - 使用
@DeleteOperation
来定义 DELETE 操作。
4.10、扩展现有端点 {#410扩展现有端点}
假如我们想确保应用的生产实例永远不会是 SNAPSHOT
版本。
为此,我们决定改变返回该信息的 Actuator
端点(即 /info
)的 HTTP 状态码。如果应用程序碰巧是 SNAPSHOT,就返回不同的 HTTP 状态码。
可以使用 @EndpointExtension
注解或其更具体的 @EndpointWebExtension
或 @EndpointJmxExtension
轻松扩展预定义端点的行为:
@Component
@EndpointWebExtension(endpoint = InfoEndpoint.class)
public class InfoWebEndpointExtension {
private InfoEndpoint delegate;
// 构造函数
@ReadOperation
public WebEndpointResponse<Map> info() {
Map<String, Object> info = this.delegate.info();
Integer status = getStatus(info);
return new WebEndpointResponse<>(info, status);
}
private Integer getStatus(Map<String, Object> info) {
// 如果是 snapshot 则返回 500
return 200;
}
}
4.11、启用所有端点 {#411启用所有端点}
为了通过 HTTP 访问 actuator 端点,需要同时启用和暴露它们。
默认情况下,除 /shutdown
之外的所有端点都已启用。但是,只有 /health
和 /info
端点是公开的。
可以添加以下配置来暴露所有端点:
management.endpoints.web.exposure.include=*
也可以明确启用特定端点(如 /shutdown
):
management.endpoint.shutdown.enabled=true
公开除一个端点(如 /loggers
)之外的所有启用端点,
management.endpoints.web.exposure.include=*
management.endpoints.web.exposure.exclude=loggers
5、总结 {#5总结}
本文介绍了 Spring Boot Actuator 含义及其作用。以及如何使用、调整和扩展它。
Ref:https://www.baeldung.com/spring-boot-actuators