[Spring Cloud系列]Consul-番外篇『自定义健康检查』

继续上一篇文章,猿Why最近与Consul杠上了。也是因为有这样一个需求:“服务启动(注册)失败请款下,要求Consul通过HTTP方式对服务进行健康检查,检查结果是critical”。我对这个“失败”的想法是比较多的,比如:中间件、数据源访问不通,我也可以认为是失败。那情况不就复杂了吗?
最开始的路线是通过一个事件(失败、异常事件)去触发:builder.down()。对,依然是要基于

   <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
   </dependency>

找到一篇很不错的文章,介绍Actuator。这一part猿Why就不重复记录了。

Actuator如何支持自定义健康检查

实现HealthIndicator或者直接(间接)继承AbstractHealthIndicator。至于如何实现,参考代码如下:

public class ConsulHealthIndicator extends AbstractHealthIndicator {

	private ConsulClient consul;

	public ConsulHealthIndicator(ConsulClient consul) {
		this.consul = consul;
	}

	@Override
	protected void doHealthCheck(Health.Builder builder) throws Exception {
		final Response<String> leaderStatus = this.consul.getStatusLeader();
		final Response<Map<String, List<String>>> services = this.consul
				.getCatalogServices(QueryParams.DEFAULT);
		builder.up().withDetail("leader", leaderStatus.getValue()).withDetail("services",
				services.getValue());
	}

}

自定义的健康检查如何生效

核心API:org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorRegistryBeans#get(ApplicationContext applicationContext)
思路:在Actuator加载初始化的时候,会根据类型HealthIndicator找到Bean,放到一个Map<String, HealthIndicator>。健康检查API被调用的时候,遍历这个Map,是生成健康检查的结果。

final class HealthIndicatorRegistryBeans {

	private HealthIndicatorRegistryBeans() {
	}

	public static HealthIndicatorRegistry get(ApplicationContext applicationContext) {
		Map<String, HealthIndicator> indicators = new LinkedHashMap<>();
		indicators.putAll(applicationContext.getBeansOfType(HealthIndicator.class));
		if (ClassUtils.isPresent("reactor.core.publisher.Flux", null)) {
			new ReactiveHealthIndicators().get(applicationContext).forEach(indicators::putIfAbsent);
		}
		HealthIndicatorRegistryFactory factory = new HealthIndicatorRegistryFactory();
		return factory.createHealthIndicatorRegistry(indicators);
	}

	private static class ReactiveHealthIndicators {

		public Map<String, HealthIndicator> get(ApplicationContext applicationContext) {
			Map<String, HealthIndicator> indicators = new LinkedHashMap<>();
			applicationContext.getBeansOfType(ReactiveHealthIndicator.class)
					.forEach((name, indicator) -> indicators.put(name, adapt(indicator)));
			return indicators;
		}

		private HealthIndicator adapt(ReactiveHealthIndicator indicator) {
			return () -> indicator.health().block();
		}

	}

}

健康检查结果是如何构造的

核心API:org.springframework.boot.actuate.health.Health.Builder
源码有点长,我就不全部粘贴过来占篇幅了。Builder内部有一个status状态,和details。status用于标记此项健康检查是否通过,details用于存放一些具体信息。

public static class Builder {

		private Status status;

		private Map<String, Object> details;
//……此处省略很多代码
}

然后来看一下我的Demo效果(实验做完的时候有两个小知识点):
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201202230442978.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTA3MzA3MzE=,size_16,color_FFFFFF,t_70

如果要显示其中一项,自然也是可以:
在这里插入图片描述

知识点一

/actuator/health/discoveryComposite 是服务发现配置的自定义健康检查。
核心API:org.springframework.boot.actuate.health.CompositeHealthIndicator#health
这个方法导致了最后的健康检查结果的状态为“DOWN”

知识点二

/actuator/health/ 检查结果,details中可以看出,如果有一个status是“DOWN”,那么最后的结果就是“DOWN”。这个“DOWN”是如何的来的呢?
读完源码之后知道:
核心API:org.springframework.boot.actuate.health.OrderedHealthAggregator#aggregateStatus

	@Override
	protected Status aggregateStatus(List<Status> candidates) {
		// Only sort those status instances that we know about
		List<Status> filteredCandidates = new ArrayList<>();
		for (Status candidate : candidates) {
			if (this.statusOrder.contains(candidate.getCode())) {
				filteredCandidates.add(candidate);
			}
		}
		// If no status is given return UNKNOWN
		if (filteredCandidates.isEmpty()) {
			return Status.UNKNOWN;
		}
		// Sort given Status instances by configured order
		filteredCandidates.sort(new StatusComparator(this.statusOrder));
		return filteredCandidates.get(0);
	}

原来是org.springframework.boot.actuate.health.CompositeHealthIndicator#health中的算法,挑选了第一个众多健康检查项中的第一个检查结果作为/actuator/health的最终结果。猿Why认为这样依然有一定的随机性。如果是所有检查项来一个与操作会更加合适。参考API:org.springframework.boot.actuate.health.CompositeHealthIndicator。可以对最后这个选择状态计算进行自定义。

consul dev

如果说是为了做DEMO练习,就完全没有必要去搭建一个集群模式的Consul服务。开发模式启动一个即可。
consul下载:官方链接
启动命令(以Windows cmd为例):

E:\consul_1.9.0_windows_amd64>consul.exe agent -dev -log-file="\data\consul.log"
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值