蚂蚁SOFA系列(2) - SOFABoot的Readiness健康检查机制
作者:404,公众号404P,转载请注明出处。
前言
SOFABoot是蚂蚁金服的开源框架,在原有Spring Boot的基础上增强了不少能力,例如Readiness Check,类隔离,日志空间隔离等能力。除此之外,SOFABoot还可以方便的整合SOFA技术栈所包含的各类中间件。如果想要对SOFABoot有体感,可以参考这里快速构建一个SOFABoot的应用。
本文来聊聊SOFABoot新增的Readiness健康检查机制。主要内容有以下几点:
- liveness 和 readiness 的含义和区别
- SOFABoot项目如何使用readiness的能力
- SOFABoot是如何实现readiness的
一 Liveness 和Readiness
服务的健康检查,是微服务的基础能力,在微服务的运行时期定时地检查服务健康状态,为熔断降级等提供决策依据。那么说到健康检查,这里提出两个概念:liveness和readiness。这两个概念什么意思呢?有何区别呢?我们先看看在容器编排领域,k8s官网是在什么场景下提到这两个词的。
The kubelet uses liveness probes to know when to restart a Container. For example, liveness probes could catch a deadlock, where an application is running, but unable to make progress. Restarting a Container in such a state can help to make the application more available despite bugs.
The kubelet uses readiness probes to know when a Container is ready to start accepting traffic. A Pod is considered ready when all of its Containers are ready. One use of this signal is to control which Pods are used as backends for Services. When a Pod is not ready, it is removed from Service load balancers.
kubelet用liveness探针来检测应用在运行的过程中何时该重启一个容器。例如,liveness探针检测到一个应用在运行中陷入死锁状态,毫无进展,那么这个时候会重启容器暂时避免这种无解的运行状态,保持应用的正常运行。
kuelet用readiness探针来检测何时一个容器可以接受业务流量。当一个Pod中的所有容器都准备就绪了,这个Pod才被认为是准备就绪的,这个时候才会将容器放入到Service的负载均衡池中,对外提供服务。
所以,liveness的职责是在服务运行期,已经在跑业务时,定时检查服务是否正常;而readiness的职责则是在应用服务运行之前,判断该服务是否准备就绪,如果服务就绪了,负载均衡就可以将业务流量引入到该服务了。服务就绪往往有很多需要判断的,例如:各项配置是否加载完毕。如果这些提供服务前的准备工作未就绪,这个时候把流量放进来,就会有大量报错。
二 SOFABoot项目中使用Readiness Check
Readiness Check 在 SOFABoot中是个可选能力,通过starter的方式提供,如果需要使用,引入下方依赖即可:
<dependency>
<groupId>com.alipay.sofa</groupId>
<artifactId>healthcheck-sofa-boot-starter</artifactId>
</dependency>
该starter包含了SpringBoot的健康检查spring-boot-starter-actuator。
在应用启动时,即可启动Readiness检查。
三 SOFABoot如何实现Readiness Check
我们到healthcheck-sofa-boot-starter对应的spring.factories文件看看有哪些自定义bean,其配置如下:
org.springframework.context.ApplicationContextInitializer=\
com.alipay.sofa.healthcheck.initializer.SofaBootHealthCheckInitializer
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.alipay.sofa.healthcheck.configuration.SofaBootHealthCheckAutoConfiguration
配置了两个SOFABoot的实现类,一个是用应用初始化组件,一个是SOFABoot健康检查需要的配置类。
1 应用初始化
SofaBootHealthCheckInitializer
这个是SOFABoot对于ApplicationContextInitializer的实现,这个接口的主要职责是:在springcontext 刷新(refresh)之前,调用该接口的initialize做前置的初始化操作,我们看看SOFABoot初始化做了什么事情:
public class SofaBootHealthCheckInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
Environment environment = applicationContext.getEnvironment();
if (SOFABootEnvUtils.isSpringCloudBootstrapEnvironment(environment)) {
return;
}
LOGGER.info("SOFABoot HealthCheck Starting!");
}
}
初始化的时候,判断了当前是否为SpringCloud的引导上下文,如果是的话,则返回,不打印日志,如果不是的话,则打印日志。
这是什么逻辑? 首先,初始化逻辑里只做了一件事情:打印日志,并且是在非SpringCloud环境下才打印日志?其实这是一个兼容逻辑。在SpringCloud环境下,自定义的initializer会被调用两次initialize方法(参考 # issue1151 & # issue 232),SpringCloud会加载一个引导上下文(bootstrap context)进来,我们自己的应用程序会加载应用上下文(application context)进来,这两个同时存在,intialzie会调用两次。
isSpringCloudBootstrapEnvironment方法就是为了区分是否为SpringCloud加载进来的引导上下文,从而屏蔽掉这次initialize执行,确保日志只会在应用上下文时输出,该方法主要是通过是否存在SpringCloud中的特定类来识别是否引入SpringCloud,这里就不赘述了,读者可自行查看。
2 SOFABoot实现Readiness的核心逻辑
2.1 核心Bean介绍
SofaBootHealthCheckAutoConfiguration
要搞清楚实现Readiness的核心实现,我们先看下SOFABoot到底装配了哪些bean,下面列了一些核心的bean。
@Configuration
public class SofaBootHealthCheckAutoConfiguration {
@Bean
public ReadinessCheckListener readinessCheckListener() {
return new ReadinessCheckListener();
}
@Bean
public HealthCheckerProcessor healthCheckerProcessor() {
return new HealthCheckerProcessor();
}
@Bean
public HealthIndicatorProcessor healthIndicatorProcessor() {
return new HealthIndicatorProcessor();
}
@Bean
public AfterReadinessCheckCallbackProcessor afterReadinessCheckCallbackProcessor() {
return new AfterReadinessCheckCallbackProcessor();
}
}
上面一共罗列了4个bean,一个是应用监听器ReadinessCheckListener,这个是入口逻辑,下文核心逻辑讲解将从这个类开始。
一个是Readiness检查完毕的后置处理器AfterReadinessCheckCallbackProcessor,这个职责也比较容易理解,当Readiness完成之后,就会执行去处理逻辑。
另外两个处理器则是健康检查的处理器,HealthCheckerProcessor是针对SOFABoot提供的HealthChecker类型的bean进行处理,HealthIndicatorProcesso是针对SpringBoot提供的HealthIndicator类型的bean进行处理。
2.2 核心逻辑解析
ReadinessCheckListener
这个监听器实现了ApplicationListener,并监听ContextRefreshedEvent事件,当应用上下文刷新完成后,触发监听器收到该事件,执行下面的逻辑。
// ReadinessCheckListener 接收到刷新事件后的执行逻辑
public void onApplicationEvent(ContextRefreshedEvent event) {
if (applicationContext.equals(event.getApplicationContext())) {
healthCheckerProcessor.init();
healthIndicatorProcessor.init();
afterReadinessCheckCallbackProcessor.init();
readinessHealthCheck();
readinessCheckFinish = true;
}
}
接收到上下文的刷新事件后,主要做了四件事情,前面三件是为最后一件事情做准备的:
- 健康检查处理器初始化,将上下文中所有HealthChecker类型的bean都放在map中,等待Readiness检查。
- 健康指标处理器初始化,将上下文中所有ReactiveHealthIndicator类型的bean都放在map中,等待Readiness检查。
- Readiness检查后置处理器初始化,将上下文中所有的ReadinessCheckCallback类型的bean都放在map中,等待Readiness检查完毕后调用。
- Readiness健康检查,前面三步已经准备好了HealthChecker、ReactiveHealthIndicator和ReadinessCheckCallback的所有bean,这一步是真正开始Readiness健康检查。Readiness检查核心逻辑如下:
public void readinessHealthCheck() {
if (skipAllCheck()) {
logger.warn("Skip all readiness health check.");
} else {
if (skipComponent()) {
logger.warn("Skip HealthChecker health check.");
} else {
healthCheckerStatus = healthCheckerProcessor
.readinessHealthCheck(healthCheckerDetails);
}
if (skipIndicator()) {
logger.warn("Skip HealthIndicator health check.");
} else {
healthIndicatorStatus = healthIndicatorProcessor
.readinessHealthCheck(healthIndicatorDetails);
}
}
healthCallbackStatus = afterReadinessCheckCallbackProcessor
.afterReadinessCheckCallback(healthCallbackDetails);
if (healthCheckerStatus && healthIndicatorStatus && healthCallbackStatus) {
logger.info("Readiness check result: success");
} else {
logger.error("Readiness check result: fail");
}
}
从上面的逻辑,我们可以看到HealthChecker和HealthIndicator的处理都是可以基于配置跳过的,不是必须执行的。当HealthChecker、HealthIndicator、ReadinessCheckCallback对应的处理器都执行成功之后,打印相应的结果信息。
- healthCheckerProcessor的readinessHealthCheck主要是去收集每一个HealthChecker的检查结果,当所有HealthChecker的检查结果都为true时,返回true。这个过程持续时间比较长,如果一个HealtchChecker返回的结果是false,processor会定时重试再去获取其结果,直到其返回true或者重试到最大次数。
- healthIndicatorProcessor的readinessHealthCheck逻辑和healthCheckerProcessor的类似,去收集每一个HealthIndicator的指标的具体信息,但持续过程比较短,无需重试,执行完成则返回true。
- afterReadinessCheckCallbackProcessor在Readiness检查完毕之后,逐一去调用所有ReadinessCheckCallback类型的bean,执行readiness的后置处理。
核心逻辑,其实就是三个不同类型Bean的处理器,去遍历执行各自的bean集合,收集执行结果。
- HealthChecker类型:这个是SOFABoot提供的,其处理器是SOFABoot提供的,处理器去遍历执行时需要重试获取检查结果。
- ReactiveHealthIndicator类型:这个是SpringBoot本身提供的,其处理器是SOFABoot提供的,用于处理SpringBoot本身的健康检查,处理器遍历执行时无需重试获取检查结果。
- ReadinessCheckCallback类型:这个是SOFABoot提供的,其处理器是SOFABoot提供的,Readiness检查后的后置处理bean。
可以看出,SOFABoot提供的HealthChecker和SpringBoot提供的HealthIndicator职责有点类似,但是存在差异性,HealthChecker中是适合于Readiness的,其实现类指明重试次数retryCount和重试间隔retryTimeInterval,在应用刚启动时候,做Readiness检查不一定能一次性成功,那么就需要这种最大重试机制,所以HealthChecker的处理器在readinessHealthCheck过程中持续的时间会更长。
public interface HealthChecker {
// some method..
default int getRetryCount() {
return 0;
}
default long getRetryTimeInterval(){
return 0;
}
// some method..
}
而SpringBoot本身提供的是Liveness机制,所以HealthIndicator在运行期间,本身就是一直定时去获取的,没有最大重试次数,只要一直在运行,就要定时去检查。
public interface HealthIndicator {
// Return an indication of health.
Health health();
}
当然,SOFABoot在重试完成了HealthCheck的健康检查之后,再完成了一遍HealthIndicator的健康检查,且执行了一遍后置逻辑,都成功之后,检查结果才是健康的,才可以正式对外提供服务。
显然,要扩展自己的检查指标也是很容易的,如果是要Readiness Check的,则实现一个HealthCheck类,如果是需要Liveness Check的,则实现一个HealthIndicator即可。
四 结语
本文开篇介绍了SOFABoot和SpringBoot的关系,在SpringBoot的健康检查中,提供了Liveness Check能力,SOFABoot在此之上新增了Readiness Check能力。通过starter的配置一步一步找到其入口逻辑,并对应用监听器、HealthCheck、HealthIndicator和ReadinessCheckCallback对应的三个处理的逻辑进行了核心解读,并说明了HealthCheck和HealthIndicator的区别。

近期文章:
蚂蚁SOFA系列(2) - SOFABoot的Readiness健康检查机制的更多相关文章
- Knative Serving 健康检查机制分析
作者| 阿里云智能事业群技术专家牛秋霖(冬岛) 导读:从头开发一个Serverless引擎并不是一件容易的事情,今天咱们就从Knative的健康检查说起.通过健康检查这一个点来看看Serverles ...
- 为你的docker容器增加一个健康检查机制
1.健康检查 在分布式系统中,经常需要利用健康检查机制来检查服务的可用性,防止其他服务调用时出现异常.自 1.12 版本之后,Docker 引入了原生的健康检查实现. 如何给Docke配置原生健康检查 ...
- Spring Cloud Alibaba Nacos 的 2 种健康检查机制!
Spring Cloud Alibaba Nacos 作为注册中心不止提供了服务注册和服务发现功能,它还提供了服务可用性监测的机制.有了此机制之后,Nacos 才能感知服务的健康状态,从而为服务调用者 ...
- Eureka心跳健康检查机制和Spring boot admin 节点状态一直为DOWN的排查(忽略某一个节点的健康检查)
https://www.jdon.com/springcloud/eureka-health-monitoring.html 运行阶段执行健康检查的目的是为了从Eureka服务器注册表中识别并删除不可 ...
- 蚂蚁SOFA系列(1) - 聊聊SOFA的模块化
作者:404,转载请注明出处.欢迎关注公众号:404P. SOFA是蚂蚁自研的一套金融级分布式中间件,目前正在逐步向业界开源.SOFA的全称有两个,最早是Service Oriented Fabric ...
- Docker系列(五):.Net Core实现k8s健康探测机制
k8s通过liveness来探测微服务的存活性,判断什么时候该重启容器实现自愈.比如访问 Web 服务器时显示 500 内部错误,可能是系统超载,也可能是资源死锁,此时 httpd 进程并没有异常退出 ...
- aspnetcore.webapi实践k8s健康探测机制 - kubernetes
1.浅析k8s两种健康检查机制 Liveness k8s通过liveness来探测微服务的存活性,判断什么时候该重启容器实现自愈.比如访问 Web 服务器时显示 500 内部错误,可能是系统超载,也可 ...
- aspnetcore.webapi实战k8s健康探测机制 - kubernetes
1.浅析k8s两种健康检查机制 Liveness k8s通过liveness来探测微服务的存活性,判断什么时候该重启容器实现自愈.比如访问 Web 服务器时显示 500 内部错误,可能是系统超载,也可 ...
- 9-lvs-lvs集群-及keepalived健康检查
注意: 配置前需要将上一篇的配置都清除掉 ifconfig eth1: down service ipvsadm restart nginx作为请求分发服务器时, 有健康检查机制, 挂了的服务器不会在 ...
随机推荐
- Python之assert断言语句
关键字assert构成断言语句,主要是可以在我们书写一个新的程序时,可以使用它帮我们锁定bug范围. 表达式: assert 表达式 ‘窗口提示的信息’ 括号中的项目为选填项目,选填项目将会在表达式的 ...
- 2019上半年总结——Github上那些Java面试、学习相关仓库
分享一下最近逛Github看到了一些对于Java面试以及学习有帮助的仓库,这些仓库涉及Java核心知识点整理.Java常见面试题.算法.基础知识点比如网络和操作系统等等. 知识点相关 1.JavaGu ...
- java并发编程(八)----(JUC)CountDownLatch
CountDownLatch 是一个非常实用的多线程控制工具类." Count Down " 在英文中意为倒计数, Latch 为门问的意思.如果翻译成为倒计数门阀, 我想大家都会 ...
- Promise 学习心得
当了这么久码农到今天没事才开始去深究 Promise 这个对象 什么是 Promise, Promise 有什么用? 在写代码的时候多多少少都有遇见过地狱式的回调 代码看起来没问题就是有点乱,Prom ...
- SonarQube部署及代码质量扫描入门教程
一.前言 1.本文主要内容 CentOS7下SonarQube部署 Maven扫描Java项目并将扫描结果提交到SonarQube Server SonarQube扫描报表介绍 2.环境信息 工具/环 ...
- .net core + mvc 手撸一个代码生成器
最近闲来无事,总想倒腾点什么,索性弄下代码生成器,这里感谢叶老板FreeSql的强大支持. 以前也用过两款不错的代码生成器,这里说说我的看法 1.动软代码生成器,优点很明显,免费,简单,但是没法高度自 ...
- 你真的了JMeter解聚合报告么?
1.背景 大家在使用JMeter进行性能测试时,聚合报告(Aggregate Report)可以说是必用的监听器,但是你真的了解聚合报告么? 2.目的 本次笔者跟大家聊聊聚合报告(Aggregate ...
- app登录接口请求报:“签名验证失败”???已解决
根据抓包数据获得url.param.header,在charles中compose请求结果为成功,在pycharm中运行则报:“签名验证失败”. 运行结果:
- 如果有人问你 Dubbo 中注册中心工作原理,就把这篇文章给他
注册中心作用 开篇首先想思考一个问题,没有注册中心 Dubbo 还能玩下去吗? 当然可以,只要知道服务提供者地址相关信息,消费者配置之后就可以调用.如果只有几个服务,这么玩当然没问题.但是生产服务动辄 ...
- Spring Cloud Stream 核心概念
Spring Cloud Stream简介 Spring cloud stream是一个构建与Spring Boot和Spring Integration之上的框架,方便开发人员快速构建基于Messa ...