1.概述
Spring Boot提供了几种不同的方法来检查正在运行的应用程序及其组件的状态和运行状况。在这些方法中, HealthContributor
和HealthIndicator
API是其中两个。
在本教程中,我们将熟悉这些API,了解它们的工作原理,并了解如何为它们提供定制信息。
2.依赖关系
健康信息贡献者是Spring Boot执行器模块的一部分,因此我们需要适当的Maven依赖项:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
3.内置的HealthIndicator
Spring Boot开箱即用地注册了许多HealthIndicator
以报告特定应用程序方面的运行状况。
这些指标中的一些几乎总是被注册的,例如DiskSpaceHealthIndicator
或PingHealthIndicator
。前者报告磁盘的当前状态,后者充当应用程序的ping端点。
另一方面,Spring Boot有条件地注册一些指示器。也就是说,如果某些依赖关系在类路径上,或者满足其他一些条件,Spring Boot可能还会注册其他一些HealthIndicator
。例如,如果我们使用关系数据库,那么Spring Boot注册DataSourceHealthIndicator
。同样,如果我们碰巧将Cassandra用作数据存储,它将注册CassandraHealthIndicator
为了检查Spring Boot应用程序的运行状况,我们可以调用/actuator/health
端点。该端点将报告所有已注册HealthIndicator
的汇总结果。
另外,要从一个特定指标查看运行状况报告,我们可以调用/actuator/health/{name}
端点。例如,调用/actuator/health/diskSpace
DiskSpaceHealthIndicator
返回状态报告:
{
"status": "UP",
"details": {
"total": 499963170816,
"free": 134414831616,
"threshold": 10485760,
"exists": true
}
}
4.自定义HealthIndicator
除了内置的健康指标外,我们还可以注册自定义HealthIndicator
以报告组件或子系统的健康状况。为此,我们要做的就是将HealthIndicator
接口的实现注册为Spring bean 。
例如,以下实现随机报告失败:
@Component
public class RandomHealthIndicator implements HealthIndicator {
@Override
public Health health() {
double chance = ThreadLocalRandom.current().nextDouble();
Health.Builder status = Health.up();
if (chance > 0.9) {
status = Health.down();
}
return status.build();
}
}
根据此指标的运行状况报告,应仅在90%的时间内启动应用程序。这里,我们使用Health
建设者上报的健康信息。
**但是,在反应式应用程序中,我们应该注册一个ReactiveHealthIndicator
**类型的Bean。反应性health()
方法返回Mono<Health>
而不是简单的Health
。除此之外,这两种Web应用程序类型的其他详细信息都相同。
4.1 指标名称
要查看有关该特定指标的报告,我们可以调用/actuator/health/random
端点。例如,下面是API响应的样子:
{"status": "UP"}
在random
的/actuator/health/random
URL是该指示器的标识。 HealthIndicator
实现的标识符**等于不带HealthIndicator
**后缀的Bean名称。由于bean名称是randomHealthIdenticator
,所以random
前缀将是标识符。
使用此算法,如果我们将bean名称更改为rand
:
@Component("rand")
public class RandomHealthIndicator implements HealthIndicator {
// omitted
}
然后,指标标识符将是rand
而不是random
。
4.2 禁用指标
要禁用特定指示器,我们可以将“
management.health.<indicator_identifier>.enabled”
配置属性设置为false
。例如,如果我们将以下内容添加到application.properties
:
management.health.random.enabled=false
然后,Spring Boot将禁用RandomHealthIndicator
。要激活此配置属性,我们还应该在指标上@ConditionalOnEnabledHealthIndicator
@Component
@ConditionalOnEnabledHealthIndicator("random")
public class RandomHealthIndicator implements HealthIndicator {
// omitted
}
现在,如果我们调用/actuator/health/random
,Spring Boot将返回404 Not Found HTTP响应:
@SpringBootTest
@AutoConfigureMockMvc
@TestPropertySource(properties = "management.health.random.enabled=false")
class DisabledRandomHealthIndicatorIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Test
void givenADisabledIndicator_whenSendingRequest_thenReturns404() throws Exception {
mockMvc.perform(get("/actuator/health/random"))
.andExpect(status().isNotFound());
}
}
请注意,禁用内置或自定义指标彼此相似。因此,我们也可以将相同的配置应用于内置指示器。
4.3 额外细节
除了报告状态外,我们还可以使用withDetail(key, value)
附加其他键值详细信息:
public Health health() {
double chance = ThreadLocalRandom.current().nextDouble();
Health.Builder status = Health.up();
if (chance > 0.9) {
status = Health.down();
}
return status
.withDetail("chance", chance)
.withDetail("strategy", "thread-local")
.build();
}
在这里,我们向状态报告中添加了两条信息。另外,我们可以通过将Map<String, Object>
传递给withDetails(map)方法来实现相同的目的:
Map<String, Object> details = new HashMap<>();
details.put("chance", chance);
details.put("strategy", "thread-local");
return status.withDetails(details).build();
现在,如果我们调用/actuator/health/random
,我们可能会看到类似以下内容:
{
"status": "DOWN",
"details": {
"chance": 0.9883560157173152,
"strategy": "thread-local"
}
}
我们也可以通过自动测试来验证此行为:
mockMvc.perform(get("/actuator/health/random"))
.andExpect(jsonPath("$.status").exists())
.andExpect(jsonPath("$.details.strategy").value("thread-local"))
.andExpect(jsonPath("$.details.chance").exists());
与系统组件(例如数据库或磁盘)通信时,有时会发生异常。我们可以使用withException(ex)方法报告此类异常:
if (chance > 0.9) {
status.withException(new RuntimeException("Bad luck"));
}
我们还可以将异常传递给前面看到down(ex)
if (chance > 0.9) {
status = Health.down(new RuntimeException("Bad Luck"));
}
现在,运行状况报告将包含堆栈跟踪:
{
"status": "DOWN",
"details": {
"error": "java.lang.RuntimeException: Bad Luck",
"chance": 0.9603739107139401,
"strategy": "thread-local"
}
}
4.4 细节曝光
management.endpoint.health.show-details
配置属性控制每个运行状况终结点可以公开的详细信息级别。
例如,如果我们将此属性设置为always,
那么Spring Boot将总是返回details
字段,就像上面的示例一样。
另一方面,如果我们将此属性设置为never
,那么Spring Boot将始终忽略output中details
。还有一个when_authorized
值,仅向授权用户details
用户只有在以下情况下才能获得授权:
- 她已通过身份验证
- 她拥有在
management.endpoint.health.roles
配置属性中指定的角色
4.5 健康状况
默认情况下,Spring Boot定义四个不同的值作为运行Status`:
-
UP —
组件或子系统按预期工作 -
DOWN
—组件不起作用 -
OUT_OF_SERVICE
—组件暂时停止服务 -
UNKNOWN
—组件状态未知
这些状态被声明为[public static final](https://github.com/spring-projects/spring-boot/blob/310ef6e9995fab302f6af8b284d0a59ca0f212e9/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/Status.java#L43)
实例,而不是Java枚举。因此可以定义我们自己的自定义健康状态。为此,我们可以使用[status(name)](https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/actuate/health/Health.Builder.html#status-java.lang.String-)
方法:
Health.Builder warning = Health.status("WARNING");
健康状况会影响健康终结点的HTTP状态代码。默认情况下,Spring Boot映射DOWN
和OUT_OF_SERVICE
状态以抛出503状态代码。另一方面, UP
和任何其他未映射状态将转换为200 OK状态代码。
要自定义此映射,我们可以将management.endpoint.health.status.http-mapping.<status>
配置属性设置为所需的HTTP状态代码号:
management.endpoint.health.status.http-mapping.down=500
management.endpoint.health.status.http-mapping.out_of_service=503
management.endpoint.health.status.http-mapping.warning=500
现在Spring Boot将DOWN
状态映射到500,将OUT_OF_SERVICE
到503,将WARNING
映射到500 HTTP状态代码:
mockMvc.perform(get("/actuator/health/warning"))
.andExpect(jsonPath("$.status").value("WARNING"))
.andExpect(status().isInternalServerError());
同样, [HttpCodeStatusMapper](https://docs.spring.io/spring-boot/docs/2.2.3.RELEASE/api/org/springframework/boot/actuate/health/HttpCodeStatusMapper.html)
类型的bean来自定义HTTP状态代码映射:
@Component
public class CustomStatusCodeMapper implements HttpCodeStatusMapper {
@Override
public int getStatusCode(Status status) {
if (status == Status.DOWN) {
return 500;
}
if (status == Status.OUT_OF_SERVICE) {
return 503;
}
if (status == Status.UNKNOWN) {
return 500;
}
return 200;
}
}
getStatusCode(status)
方法将运行状况作为输入,并返回HTTP状态代码作为输出。此外,还可以映射自定义的Status
实例:
if (status.getCode().equals("WARNING")) {
return 500;
}
默认情况下,Spring Boot使用默认映射注册此接口的简单实现。 [SimpleHttpCodeStatusMapper](https://docs.spring.io/spring-boot/docs/2.2.3.RELEASE/api/org/springframework/boot/actuate/health/SimpleHttpCodeStatusMapper.html)
还能够从配置文件中读取映射。
5.健康信息与指标
非平凡的应用程序通常包含一些不同的组件。例如,考虑使用Cassandra作为数据库,使用Apache Kafka作为其发布-订阅平台,使用Hazelcast作为其内存数据网格的Spring Boot应用程序。
我们应该使用HealthIndicator
来查看应用程序是否可以与这些组件进行通信。如果通信链接失败,或者组件本身发生故障或运行缓慢,则我们应了解组件状态不正常。换句话说,这些指标应用于报告不同组件或子系统的健康状况。
相反,我们应该避免使用HealthIndicator
来测量值,对事件进行计数或测量持续时间。这就是为什么我们有指标。简而言之,指标是报告CPU使用率,平均负载,堆大小,HTTP响应分布等的更好工具。
六,结论
在本教程中,我们看到了如何向执行器运行状况端点贡献更多的运行状况信息。此外,我们深入介绍了健康API中的不同组件,例如Health
, Status
和HTTP状态映射的状态。
最后,我们就健康信息和指标之间的区别进行了快速讨论,并了解了何时使用它们。
像往常一样,所有示例都可以 在GitHub上找到。
0 评论