环境介绍
开发依赖 | 版本 |
---|---|
Spring Boot | 3.0.6 |
JDK | 20 |
主要的pom依赖
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
不能使用/actuator/health来做健康检查
因为/health
进行严格检查SpringBoot
各项组件服务,比如邮件服务、数据库服务、MQ服务等,当发现有一个组件处于非正常状态,其返回的内容会由{"status": "up"}
变为{"status": "down"}
,从而导致Liveness
探针失效,而有些情况下,还抛出异常,在特定情况下某些服务不正常属于正常现象,例如:邮件服务。
我们在一次邮件服务迁移的过程中,使用
Liveness
探针频繁访问/health
,触发了springboot
连续抛出堆栈信息导致服务直接宕机,非常恐怖,如果没有做到宕机快照,会导致查问题无从下手
启用 liveness 和 readiness 探针
management:endpoint:health:probes:enabled: truehealth:livenessstate:enabled: truereadinessstate:enabled: true
- 从 Spring Boot 2.3 开始,LivenessStateHealthIndicator 和 ReadinessStateHealthIndicator 类将公开应用程序的活跃度和就绪状态。 当将应用程序部署到 Kubernetes 时,Spring Boot 会自动注册这些健康指标。
- 因此,可以分别使用 /actuator/health/liveness 和 /actuator/health/readiness 端点作为liveness 和 readiness 探针。
livenessProbe:httpGet:path: /actuator/health/livenessport: 18080initialDelaySeconds: 5failureThreshold: 2periodSeconds: 60
readinessProbe:httpGet:path: /actuator/health/readinessport: 18080initialDelaySeconds: 5periodSeconds: 60
startupProbe:httpGet:path: /actuator/health/readinessport: 18080failureThreshold: 30periodSeconds: 10
原理
Spring Boot
使用两个枚举来封装不同的就绪和活跃状态。 对于就绪状态,有一个名为 ReadinessState
的枚举,具有以下值:
ACCEPTING_TRAFFIC
状态表示应用程序已准备好接受流量REFUSING_TRAFFIC
状态意味着应用程序还不愿意接受任何请求
同样,LivenessState
枚举使用两个值表示应用程序的活跃状态:
CORRECT
值表示应用程序正在运行并且其内部状态是正确的- 另一方面,
BROKEN
值意味着应用程序运行时出现了一些致命故障
以下是 Spring
中应用程序生命周期事件方面的就绪和活跃状态如何变化:
- 注册监听器和初始化器
- 准备环境
- 准备应用程序上下文
- 加载
bean
定义 - 将活动状态更改为
CORRECT
- 调用应用程序和命令行运行程序
- 将就绪状态更改为
ACCEPTING_TRAFFIC
- 一旦应用程序启动并运行,(和
Spring
本身)就可以通过发布适当的AvailabilityChangeEvents
来更改这些状态。
自定义健康检查
由于预热可以看做实例能否正常提供服务的健康指标,所以我采用了rediness探针,实例代码如下:
public class SeaReadinessHealthIndicator extends AvailabilityStateHealthIndicator {private Integer isChecking = 0;private StringBuffer notCompleteExecuteClassBuffer = new StringBuffer();@Overrideprotected void doHealthCheck(Health.Builder builder) {switch (isChecking.get()) {case 1:builder.down().withDetail("message", "instance is starting.").build();return;case 2:builder.outOfService().withDetail("message", String.format("some service start error. they are: %s", notCompleteExecuteClassBuffer.toString())).build();return;case 200:builder.up().build();return;}}@Overrideprotected AvailabilityState getState(ApplicationAvailability applicationAvailability) {return applicationAvailability.getReadinessState();}
}
- 这么设置后,访问
/actuator/health/seaReadiness
,发现无法访问,再检查/actuator/health
目录,发现有一个cn.xxx.seaReadiness
的状态是{"status":"UP"}
,原来actuator health
的规则是SeaReadinessHealthIndicator
,HealthIndicator
之前的默认为名称。如果是加入扫描的方式就是这样的,但我现在是用starter的方式进行发布的。- 如果我要实现
/actuator/health/seaReadiness
访问怎么做呢?- 在
starter
扫描的类名中,加上以下别名即可:
@Component("seaReadiness")
public class SeaReadinessHealthIndicator extends AvailabilityStateHealthIndicator {}