赞
踩
SOFABoot在SpringBoot的Liveness检查能力的基础上,增加了Readiness检查能力。如果你需要使用SOFA中间件,那么建议使用SOFABoot的Readiness检查能力,来更优雅的上线应用实例。
SpringBootActuator帮助我们监控我们的SpringBoot项目。
SpringBootActuator涉及的内容比较多。在此,为了便于理解SOFABoot的Readiness检查实现原理,我们回顾一下SpringBoot的健康检查相关内容。我们只关注核心的Endpoint、HealthIndicator和Health。
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 给我们提供默认的监控结果,包含 磁盘检测和数据库检测。
Health类代表了SpringBoot组件或子系统的健康信息。
Health类使用了Builder模式,其类图如下:
1. Health类
Health类上声明了@JsonInclude(Include.NON_EMPTY)注解,表明如果该类中所有属性如果为空或为NULL,则不序列化。
Health类声明了如下字段:
2. Status类
Status类上声明了如下注解:
如果该类中的所有属性都为空或为 NULL,则不序列化。
Status类内部定义了如下字段:
Status类预定义了4个静态字段:
3. Builder类
Builder类为内部类,定义在 Health类中,其构造函数:
默认情况下,构建出来的Health状态为UNKNOWN。
通过如下方式使用 Builder 构建Health:
EndPoint依赖HealthIndicator接口的实现类提供各种比较有用的健康信息。
HealthIndicator接口实现类在org.springframework.boot.actuate.health包下,其简化类图如下:
1. HealthIndicator
HealthIndicator 是一个顶层接口,其只声明了1个方法:
2. AbstractHealthIndicator
AbstractHealthIndicator是一个抽象类,提供了一个模板方法health。
在health方法中,调用抽象方法doHealthCheck方法。该方法由子类重写,完成实际的健康检查操作。
2. HealthIndicator实现类
以ApplicationHealthIndicator和DataSourceHealthIndicator为例,详细描述HealthIndicator的实现细节。
(1) ApplicationHealthIndicator
该类继承AbstractHealthIndicator,实现doHealthCheck方法。在该方法中,直接将status设置为UP。具体实现代码如下:
(2) DataSourceHealthIndicator
DataSourceHealthIndicator 中定义了如下字段:
DataSourceHealthIndicator 实现了InitializingBean接口,因此在初始化后会调用afterPropertiesSet方法,代码如下:
在DataSourceHealthIndicator类中,提供了doHealthCheck 实现:
doHealthCheck方法的处理逻辑如下:
1) 如果DataSource没有配置,则直接返回UP,message为UNKNOWN。
2) 否则,调用doDataSourceHealthCheck,代码如下:
获得数据库生产商名称,并添加至builder中,代码如下:
获得测试用的SQL语句,默认为SELECT 1。获得测试用的SQL查询语句的代码如下:
使用测试用的SQL语句进行数据库查询,将查询结果放入builder中,key为hello,value为结果值。
如果查询操作发生异常,则调用Builder.down 方法,设置状态为DOWN。
至此,DataSourceHealthIndicator类doHealthCheck处理完成。
了解了SpringBoot健康检查的原理以后,我们再来看看SOFABoot。
目前,SOFABoot中间件已经通过SOFABoot的Readiness检查能力来控制了上游流量的进入,但是一个应用的流量可能并不是全部都是从中间件进入的,比较常见的还有从负载均衡器进入的,为了控制从负载均衡器进入的流量,建议使用者通过 PAAS 来访问Readiness检查的结果,根据结果来控制是否要在负载均衡器中上线对应的节点。
看一下SOFABoot的Readiness检查相关的类图:
与SpringBoot提供的HealthIndicator相似,SOFABoot提供了HealthChecker接口。各SOFABoot中间件,通过实现HealthChecker接口,提供中间件的Readiness检查能力。例如:runtime-sofa-boot-starter提供了SofaComponentHealthChecker类,实现了SOFABoot中所有注册组件的Readiness检查功能。isle-sofa-boot-starter提供了SofaModuleHealthChecker类,实现了SOFABoot模块化开发中,每个模块的的Readiness检查功能。
1. HealthChecker
HealthChecker是一个顶层接口,声明了以下5个方法:
2. HealthCheckManager
HealthCheckManager是一个工具类,为SOFABoot应用提供了获取各类健康检查接口实现类的方法,供其它健康检查处理器使用。
另外,SOFABoot关于Readiness检查功能,提供了如下扩展点:
(1)扩展 Readiness检查能力
在Readiness Check的各个阶段,SOFABoot都提供了扩展的能力,应用可以根据自己的需要进行扩展,目前可供扩展的点如下:
1. org.springframework.context.ApplicationListener
如果想要在Readiness检查之前做一些事情,那么监听这个Listener 的 SofaBootBeforeHealthCheckEvent 事件。
2. org.springframework.boot.actuate.health.HealthIndicator
如果想要在SOFABoot的Readiness检查里面增加一个Liveness检查项,那么可以实现HealthIndicator接口。
3. com.alipay.sofa.healthcheck.core.HealthChecker
如果想要在SOFABoot的Readiness检查里面增加一个Readiness检查项,那么可以实现HealthChecker接口。
4. com.alipay.sofa.healthcheck.startup.SofaBootAfterReadinessCheckCallback
如果想要在Readiness Check之后做一些SOFABoot应用级别的事情,例如端口是否可用等,那么可以扩展SOFABoot的这个接口。
5. com.alipay.sofa.healthcheck.startup.SofaBootMiddlewareAfterReadinessCheckCallback
如果想要在Readiness Check之后做一些SOFABoot中间件级别的事情,例如某个Server是否启动成功,那么可以扩展SOFABoot的这个接口。
(2)Readiness检查配置项
应用在引入SOFABoot的健康检查扩展之后,可以在SpringBoot的配置文件 application.properties 中添加相关配置项来定制ReadinessCheck的相关行为。
1. com.alipay.sofa.healthcheck.skip.all:是否跳过整个Readiness检查阶段默认值:false;
2. com.alipay.sofa.healthcheck.skip.component :是否跳过SOFABoot中间件的 Readiness检查阶段,默认值:false;
3. com.alipay.sofa.healthcheck.skip.indicator:是否跳过HealthIndicator的Readiness检查阶段,默认值:false;
以SOFABoot自带的sofa-boot-sample为例,详细描述Healthcheck原理。
在此提前说明,源码分析主要分析主流程,以及本人认为比较重要的一些内容,对于其它部分,大家可以基于本文档,自行研读。
与SpringBoot最主要的特性自动配置AutoConfig一样,SOFABoot也是通过提供Healthcheck的starter,为我们自动配置。
我们只需要在项目sofa-boot-sample的pom.xml文件中,添加healthcheck-sofa-boot-starter到项目依赖中即可。
通过SpringApplication类run方法,启动项目:
本文主要详述Healthcheck相关的内容,SOFABoot的启动原理可以参考《启动原理》,在此不在详述。
由于SOFABoot 基于SpringBoot的基础上进行构建,所以完全兼容SpringBoot。作为一个遵循SpringBoot规范的Jar包,也是通过自动配置(spring.factories)和HealthcheckInitializer(实现了ApplicationContextInitializer接口)完成Healthcheck的初始化工作和Healthcheck相关Bean的注册和服务的启动。
healthcheck-sofa-boot-starter模块的spring.factories文件内容如下:
在SpringApplication实例初始化的时候,使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationContextInitializer接口实现类,此时会加载HealthcheckInitializer。
SpringApplication实例初始化完成后,开始执行run方法的逻辑。
1、Healthcheck初始化
在调用prepareContext方法准备Spring应用上下文过程中,依次调用刚才加载的ApplicationContextInitializer接口的实现类的initialize方法,完成Spring应用上下文的初始化工作。此时,会调用HealthcheckInitializer的initialize方法,完成Healthcheck相关的初始化工作。
HealthcheckInitializer的initialize方法主要完成两个任务:
1. Healthcheck日志空间初始化。日志空间初始化参考《日志空间隔离》,在此不详述。
2. 使用Spring应用上下文中的Environment初始化HealthCheckConfiguration的Enviroment属性;
2、Healthcheck配置类注册
在调用refreshContext方法刷新Spring应用上下文过程中,在AbstractApplicationContext类refresh方法的invokeBeanFactoryPostProcessors阶段,通过ConfigurationClassPostProcessor类开始处理@Configuration配置类。
按照spring.factories文件中EnableAutoConfiguration的配置:
healthcheck-sofa-boot-starter模块自动配置的起始配置类还是HealthcheckInitializer:
此处主要关注@ComponentScan注解,该注解的basePackageClasses属性规定了自动配置的类扫描包路径:
1. HealthCheckTrigger类所在的包com.alipay.sofa.healthcheck.startup;
2. SofaBootComponentHealthCheckInfo类所在的包com.alipay.sofa.healthcheck.service;
ConfigurationClassPostProcessor类会处理上述包中@Configuration配置类。
在com.alipay.sofa.healthcheck.startup包中,存在的@Configuration配置类为EndPointConfig:
在Spring应用上下文中注册带@Configuration注解的配置类EndPointConfig 、SofaBootReadinessCheckEndpoint、SofaBootReadinessCheckMvcEndpoint的Bean定义。同时,在Spring应用上下文中注册上述starup和service包路径中带有@Component注解的组件SofaBootComponentHealthCheckInfo、SpringContextHealthCheckInfo、HealthCheckTrigger的Bean定义。
3、Healthcheck配置类实例化
在AbstractApplicationContext类refresh方法中,调用finishBeanFactoryInitialization(beanFactory)方法实例化所有非延时加载的单例实例。此时会实例化上述注册的Healthcheck相关的Bean。
4、Healthcheck健康检查
在AbstractApplicationContext类refresh方法中,调用finishRefresh()方法,完成Spring应用上下文刷新任务。此时,会发布ContextRefreshedEvent事件,触发所有监听ContextRefreshedEvent事件的ApplicationListener接口的实现类。由于HealthCheckTrigger类实现了ApplicationListener<ContextRefreshedEvent>接口,所以在finishRefresh阶段,会调用HealthCheckTrigger的onApplicationEvent方法,完成Healthcheck初始化工作:
1. 获取Spring应用上下文;
2. 初始化HealthCheckManager:设置HealthCheckManager的静态成员变量applicationContext;
3. 在日志中打印Spring应用上下文中HealthChecker接口和HealthIndicator接口的实现类信息,例如:
4. 创建ReadinessCheckProcessor实例;
5. 调用ReadinessCheckProcessor类checkHealth方法,开始Readiness检查。整个Readiness检查共分为两个阶段:
(1) 第一阶段:startHealthCheckProcess
此方法开始第一阶段的Readiness检查:
需要注意的是,只有当所有的检查项都通过,整个第一阶段的Readiness检查结果才为true。否则为false。
1) 检查com.alipay.sofa.healthcheck.skip.all属性
此处为false,表示进行Readiness检查。需要注意的是,如果跳过所有Readiness检查,则默认Readiness检查结果为true,表示所有组件状态为正常。
2) 检查Spring应用上下文健康状态
调用SpringContextCheckProcessor类springContextCheck方法,检查Spring应用上下文健康状态:
调用HealthCheckManager类springContextCheck方法,检查Spring应用上下文健康状态:如果Spring应用上下文为AbstractApplicationContext类的实例,并且其isActive方法返回值为true,或者Spring应用上下文不为null,并且不是AbstractApplicationContext类的实例,在这两种情况下,表示Spring应用上下文健康状态为正常状态,否则为不正常状态。
设置StartUpHealthCheckStatus类属性springContextStatus为刚才健康检查的结果。
3) 检查SOFABoot组件的健康状态
调用ComponentCheckProcessor类startupCheckComponent方法,检查SOFABoot组件的健康状态(所有提供HealthChecker接口实现类的组件)。
需要注意的是,当无SOFABoot中间件需要Readiness检查或所有SOFABoot中间件的Readiness检查结果为true,整个SOFABoot中间件的Readiness检查结果才为true。否则为false。
检查com.alipay.sofa.healthcheck.skip.component属性值。此处为false,表示进行SOFABoot中间件的Readiness检查。
调用HealthCheckManager类getHealthCheckers方法,获取Spring应用上下文中所有HealthChecker接口的实现类。
然后,针对每个HealthChecker接口的实现类,调用doCheckComponentHealth方法,进行组件的Readiness检查:
组件Readiness检查处理逻辑简述如下:
首先,获取组件的健康状态实例health,如果health的status为UP,则返回true。否则,在重试次数范围内,每次间隔指定的时间,重新调用HealthChecker接口实现类的isHealthy方法,检查组件的健康状态。在循环过程中,只要某次health的status为UP,则退出循环。否则,直至达到最大重试次数。
对于检查结果,如果strictCheck属性值为false,表示非严格检查模式,则默认检查结果为true;如果strictCheck属性值为true,表示严格检查模式,则以最后一次健康检查的结果health为最终的检查结果。
需要注意的是,不同HealthChecker接口实现类的isHealthy方法是不同的。如SofaComponentHealthChecker,它会检查组件管理器中所有组件的状态(包括服务组件ServiceComponent、引用组件ReferenceComponent等),只有当所有组件的状态都为true时,SofaComponentHealthChecker才返回status为UP的Health。
另外,不同组件的isHealthy方法也是不同的。如ServiceComponent的isHealthy方法,它在组件为activated状态,并且组件发布过程中无异常发生,则表示该组件状态为true。
最后,设置StartUpHealthCheckStatus类属性componentStatus为刚才健康检查的结果。
4) 检查SpringBoot组件的健康状态
调用HealthIndicatorCheckProcessor的checkIndicator方法,检查HealthIndicator组件的健康状态(实现HealthIndicator接口的实现类)。
需要注意的是,当无HealthIndicator需要Readiness检查或所有HealthIndicator的Readiness检查结果为true,整个HealthIndicator的Readiness检查结果才为true。否则为false。
检查com.alipay.sofa.healthcheck.skip.indicator属性值。此处为false,表示进行HealthIndicator的Readiness检查。
调用HealthCheckManager类getHealthIndicator方法,获取Spring应用上下文中所有HealthIndicator接口的实现类。
然后,针对每个HealthIndicator接口的实现类,调用health方法,进行Readiness检查。每个HealthIndicator实现类health方法的实现不同,如DiskSpaceHealthIndicator,其判断指定目录下可用磁盘空间是否超过了设置的上限值。如果未超过,则status为UP,否则status为DOWN。
最后,设置StartUpHealthCheckStatus类属性healthIndicatorStatus为刚才健康检查的结果。
至此,Healthcheck健康检查工作完成。
(2) 第二阶段:operationHealthCheckProcess
如果健康检查结果为true,则调用operationHealthCheckProcess方法,开始第二阶段的Readiness检查。
调用AfterHealthCheckCallbackProcessor类checkAfterHealthCheckCallback方法:
checkAfterHealthCheckCallback方法主要包括2部分检查工作:
1) 中间件级别健康检查后回调处理
调用doMiddlewareAfterHealthCheckCallback方法:
注意:当所有SofaBootMiddlewareAfterReadinessCheckCallback接口的实现类都返回status为UP的Health,此方法才返回true。否则返回false。
调用HealthCheckManager类getMiddlewareAfterHealthCheckCallbacks方法,获取Spring应用上下文中所有SofaBootMiddlewareAfterReadinessCheckCallback接口的实现类。
然后,针对每个SofaBootMiddlewareAfterReadinessCheckCallback接口的实现类,调用onHealthy方法,进行Readiness检查。正常返回status为UP的Health实例,否则返回status为DOWN的Health实例,并把每个检查结果存入StartUpHealthCheckStatus类属性afterHealthCheckCallbackDetail中。
2) 应用级别健康检查后回调处理
当doMiddlewareAfterHealthCheckCallback方法返回true,则调用doApplicationAfterHealthCheckCallback方法:
注意:当所有SofaBootAfterReadinessCheckCallback接口的实现类都返回status为UP的Health,此方法才返回true。否则返回false。
调用HealthCheckManager类getApplicationAfterHealthCheckCallbacks方法,获取Spring应用上下文中所有SofaBootAfterReadinessCheckCallback接口的实现类。
然后,针对每个SofaBootAfterReadinessCheckCallback接口的实现类,调用getStatus方法,进行Readiness检查。正常返回UP,否则返回DOWN,并把每个检查结果存入StartUpHealthCheckStatus类属性afterHealthCheckCallbackDetail中。
至此,Readiness检查完成。
从上述的分析可以看出,只有当应用中所有的Readiness检查结果都为true时,才认为整个应用的健康状态为success。否则为fail。
5、 访问Healthcheck服务
我们可以通过浏览器查看健康检查的结果。
例如:在浏览器中输入URL:http://localhost:8080/health/readiness:
服务端接受客户端请求,具体响应流程如下:
由于Healthcheck通过SpringMVC机制对外提供服务,所以,当服务端接受到客户端发起的请求时,根据请求URL:/health/readiness,查找到名为sofaBootReadinessCheckMvcEndpoint的服务处理类SofaBootReadinessCheckEndpoint的实例,然后调用其invoke方法,处理请求:
首先,判断sofaBootReadinessCheckMvcEndpoint的委托处理类是否开启,此处为com.alipay.sofa.healthcheck.service.SofaBootReadinessCheckEndpoint的实例,且enable为true,表示开启。
然后,调用SofaBootReadinessCheckEndpoint的invoke方法:
通过StartUpHealthCheckStatus,查看应用启动时Readiness检查的结果,主要包括Spring应用上下文状态、中间件状态、HealthIndicator状态、中间件级别健康检查后回调处理完状态、应用级别健康检查后回调处理完状态。
然后根据所有这些Readiness检查的结果,构造一个代表整个应用的Health。
根据Health,创建SpringMVC响应实体对象ResponseEntity。
最后,SpringMVC以JSON数据格式,返回Readiness检查的结果。例如:本项目sofa-boot-sample的Readiness检查结果如下:
至此,SOFABoot Readiness检查解析完成。
另外,补充一点,如果输入URL:http://localhost:8080/health,则可以直接查看SpringBoot的健康检查结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。