SOFABoot在SpringBoot的Liveness检查能力的基础上,增加了Readiness检查能力。如果你需要使用SOFA中间件,那么建议使用SOFABoot的Readiness检查能力,来更优雅的上线应用实例。
一、SpringBoot健康检查
SpringBootActuator帮助我们监控我们的SpringBoot项目。
SpringBootActuator涉及的内容比较多。在此,为了便于理解SOFABoot的Readiness检查实现原理,我们回顾一下SpringBoot的健康检查相关内容。我们只关注核心的Endpoint、HealthIndicator和Health。
(一)Endpoint
Endpoint接口实现类主要用来向其它操作暴露有用的信息。通常情况下,使用SpringMVC对外提供信息服务。当然,也可以使用其它技术,例如JMX,对外提供信息服务。通过继承AbstractEndpoint抽象类,可以实现自己的Endpoint。
SpringBoot Actuator提供了许多有用的Endpoint,对SpringBoot应用提供各种监控。
Endpoint相关的类图如下所示:
常用的EndPoint主要包括:
1. /health:应用的健康状态;
2. /configprops:获取应用的配置信息,因为Spring Boot 可能发布时是单独的Jar包,配置文件可能包含其中,当我们需要检查配置文件时,可以使用ConfigpropsEndPoint 进行查看一些配置是否正确;
3. /trace:最近几次的http请求信息;
当我们访问 http://localhost:8088/health时,可以看到 HealthEndPoint 给我们提供默认的监控结果,包含 磁盘检测和数据库检测。
1. {
2. "status": "UP",
3. "diskSpace": {
4. "status": "UP",
5. "total": 398458875904,
6. "free": 315106918400,
7. "threshold": 10485760
8. },
9. "db": {
10. "status": "UP",
11. "database":"MySQL",
12. "hello": 1
13. }
14. }
(二)Health
Health类代表了SpringBoot组件或子系统的健康信息。
Health类使用了Builder模式,其类图如下:
1. Health类
Health类上声明了@JsonInclude(Include.NON_EMPTY)注解,表明如果该类中所有属性如果为空或为NULL,则不序列化。
Health类声明了如下字段:
1. // 状态
2. private final Status status;
3.
4. // 详情
5. private final Map<String, Object>details;
2. Status类
Status类上声明了如下注解:
1. @JsonInclude(Include.NON_EMPTY)
如果该类中的所有属性都为空或为 NULL,则不序列化。
Status类内部定义了如下字段:
1. // 状态码
2. private final String code;
3.
4. // 描述
5. private final String description;
Status类预定义了4个静态字段:
1. // 系统状态未知
2. public static final Status UNKNOWN = newStatus("UNKNOWN");
3.
4. //服务可用
5. public static final Status UP = newStatus("UP");
6.
7. // 服务挂掉
8. public static final Status DOWN = newStatus("DOWN");
9.
10. // 服务不可用
11. public static final Status OUT_OF_SERVICE= new Status("OUT_OF_SERVICE");
3. Builder类
Builder类为内部类,定义在 Health类中,其构造函数:
1. public Builder() {
2. this.status = Status.UNKNOWN;
3. this.details = newLinkedHashMap<String, Object>();
4. }
默认情况下,构建出来的Health状态为UNKNOWN。
通过如下方式使用 Builder 构建Health:
1. try {
2. //do some test to determine state of component
3. returnnew Health.Builder().up().withDetail("version","1.1.2").build();
4. }catch (Exception ex) {
5. returnnew Health.Builder().down(ex).build();
6. }
(三)HealthIndicator
EndPoint依赖HealthIndicator接口的实现类提供各种比较有用的健康信息。
HealthIndicator接口实现类在org.springframework.boot.actuate.health包下,其简化类图如下:
1. HealthIndicator
HealthIndicator 是一个顶层接口,其只声明了1个方法:
1. public interface HealthIndicator {
2. // 返回health
3. Health health();
4. }
2. AbstractHealthIndicator
AbstractHealthIndicator是一个抽象类,提供了一个模板方法health。
在health方法中,调用抽象方法doHealthCheck方法。该方法由子类重写,完成实际的健康检查操作。
1. public final Health health() {
2. // 1. 实例化Health$Builder
3. Health.Builder builder = newHealth.Builder();
4. try {
5. // 2. 进行状态的检查,如果在检查过程中出现异常,则状态为Status.DOWN
6. doHealthCheck(builder);
7. }
8. catch (Exception ex) {
9. this.logger.warn("Health checkfailed", ex);
10. builder.down(ex);
11. }
12. // 3. 构建Health
13. return builder.build();
14. }
2. HealthIndicator实现类
以ApplicationHealthIndicator和DataSourceHealthIndicator为例,详细描述HealthIndicator的实现细节。
(1) ApplicationHealthIndicator
该类继承AbstractHealthIndicator,实现doHealthCheck方法。在该方法中,直接将status设置为UP。具体实现代码如下:
1. protected void doHealthCheck(Health.Builderbuilder) throws Exception {
2. builder.up();
3. }
(2) DataSourceHealthIndicator
DataSourceHealthIndicator 中定义了如下字段:
1. // 默认的测试语句为SELECT 1
2. private static final String DEFAULT_QUERY= "SELECT 1";
3.
4. // 数据库资源
5. private DataSource dataSource;
6.
7. // 测试语句
8. private String query;
9.
10. private JdbcTemplate jdbcTemplate;
DataSourceHealthIndicator 实现了InitializingBean接口,因此在初始化后会调用afterPropertiesSet方法,代码如下:
1. public void afterPropertiesSet() throwsException {
2. Assert.state(this.dataSource != null,
3. "DataSource for DataSourceHealthIndicatormust be specified");
4. }
在DataSourceHealthIndicator类中,提供了doHealthCheck 实现:
1. protected voiddoHealthCheck(Health.Builder builder) throws Exception {
2. // 1. 如果DataSource没有配置,则直接返回up,message 为unknown
3. if (this.dataSource == null) {
4. builder.up().withDetail("database","unknown");
5. }
6. else {
7. // 2.
8. doDataSourceHealthCheck(builder);
9. }
10. }
doHealthCheck方法的处理逻辑如下:
1) 如果DataSource没有配置,则直接返回UP,message为UNKNOWN。
2) 否则,调用doDataSourceHealthCheck,代码如下:
1. private void doDataSourceHealthCheck(Health.Builderbuilder) throws Exception {
2. String product = getProduct();
3. builder.up().withDetail("database",product);
4. StringvalidationQuery = getValidationQuery(product);
5. if(StringUtils.hasText(validationQuery)) {
6. try{
7. //Avoid calling getObject as it breaks MySQL on Java 7
8. List<Object>results = this.jdbcTemplate.query(validationQuery,
9. newSingleColumnRowMapper());
10. Objectresult = DataAccessUtils.requiredSingleResult(results);
11. builder.withDetail("hello",result);
12. }
13. catch(Exception ex) {
14. builder.down(ex);
15. }
16. }
17. }
获得数据库生产商名称,并添加至builder中,代码如下: