Dubbo 服务启动检查

前言

大家好,今天开始给大家分享 — Dubbo 专题之 Dubbo 服务启动检测。在前面的章节中我们介绍了 Dubbo服务配置,在这个章节中我们会介绍服务启动检查。那么什么是服务启动检测呢?顾名思义就是服务启动时执行检查,那么检查什么。这样做有什么使用场景呢?那就让我们快速开始吧!

1. 服务检测简介

在 Dubbo 中提供了多种服务检查,分别是:服务提供者检查、注册中心检查 。我们可以通过配置的方式进行切换是否开启检查,默认是​​true​​下面通过三种配置方式进行说明:

1.1 xml配置方式

  1. 关闭依赖服务检查
    关闭某个服务的启动时检查
<dubbo:reference interface="com.foo.BarService" check="false" />

关闭所有服务的启动时检查

<dubbo:consumer check="false" />
  1. 关闭注册中心启动时检查
<dubbo:registry check="false" />

1.2 通过属性配置

#关闭指定接口服务检查
dubbo.reference.com.muke.dubbocourse.serviceconfig.api.BookFacade.check=false
#关闭所有引用服务检查
dubbo.reference.check=false
#关闭所有服务的启动时检查
dubbo.consumer.check=false
#关闭注册中心启动时检查
dubbo.registry.check=false

1.3 通过 JVM 参数

#关闭指定接口服务检查
java -Ddubbo.reference.com.muke.dubbocourse.serviceconfig.api.BookFacade.check=false
#关闭所有引用服务检查
java -Ddubbo.reference.check=false
#关闭所有服务的启动时检查
java -Ddubbo.consumer.check=false
#关闭注册中心启动时检查
java -Ddubbo.registry.check=false

Tips:​dubbo.reference.check=false​​​强制改变所有 ​​reference​​​ 的 ​​check​​​ 值,就算配置中有声明,也会被覆盖。​​dubbo.consumer.check=false​​​是设置 ​​check​​​ 的缺省值,如果配置中有显式的声明,如:​​<dubbo:reference check="true"/>​​​不会受影响。​​dubbo.registry.check=false​​前面两个都是指订阅成功,但提供者列表是否为空是否报错,如果注册订阅失败时,也允许启动,需使用此选项,将在后台定时重试。

2. 启动时服务检查作用

Dubbo 服务会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 容器初始化完成,以便上线时,能及早发现问题,默认 ​​check="true"​​​,即默认情况当 Dubbo 服务启动时候会去检查依赖服务是否可用。我们可以通过 ​​check="false"​​​ 关闭检查,比如,测试时,有些服务不关心,或者出现了循环依赖,必须有一方先启动。另外,如果你的 Spring 容器是懒加载的,或者通过 API 编程延迟引用服务,请关闭 ​​check​​​,否则服务临时不可用时,会抛出异常,拿到 ​​null​​​ 引用,如果 ​​check="false"​​,总是会返回引用,当服务恢复时,能自动连上。

3. 示例演示

下面我们通过一个获取书列表的例子来进行演示,代码结构如下:

Dubbo 服务启动检测_dubbo

这里主要看消费端的 xml 配置文件​​dubbo-consumer-xml.xml​​​,我们在​​<dubbo:reference>​​标签中指定了

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

<dubbo:application name="demo-consumer" logger="log4j"/>

<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<!-- <dubbo:consumer check="false" />-->
<!-- <dubbo:registry check="false" />-->

<!--当check="false"是服务提供者未启动不会报错 注意 :这里必须配置init="true"才能达到检查效果-->
<dubbo:reference id="bookFacade" init="true" check="true"
interface="com.muke.dubbocourse.common.api.BookFacade"></dubbo:reference>

</beans>

上面消费者的配置文件中我们指定了引用 Dubbo 服务​​init="true"​​​ 和​​check="true"​​​属性来确保在消费者服务启动时检查​​com.muke.dubbocourse.common.api.BookFacade​​服务提供者存在否则会抛出异常。

4. 原理分析

我们使用的​​<dubbo:reference>​​​、​​@Reference​​​、​​@DubboReference​​​引用 Dubbo 暴露的服务时都会被解析为​​ReferenceBean​​简化后的源码:

public class ReferenceBean<T> extends ReferenceConfig<T> implements FactoryBean,
ApplicationContextAware, InitializingBean, DisposableBean {

@Override
@SuppressWarnings({"unchecked"})
public void afterPropertiesSet() throws Exception {

// Initializes Dubbo's Config Beans before @Reference bean autowiring
prepareDubboConfigBeans();

// lazy init by default.
if (init == null) {
init = false;
}

// 判断是否初始化代理对象
if (shouldInit()) {
//获取代理对象
getObject();
}
}

@Override
public void destroy() {
// do nothing
}
}

从上面源码可以知道​​ReferenceBean​​​实现了​​InitializingBean​​​接口,属性 Spring 的朋友都知道这是 Bean 生命周期回调接口。当我们的 Bean 在Spring 管理的生命周期中被回调​​afterPropertiesSet​​​方法,此方法​​init​​​标记来判断是否初始化取代理对象(这个必须配置),从而触发创建代理对象。在创建代理对象时​​com.alibaba.dubbo.config.ReferenceConfig#createProxy​​​方法中会根据​​check="true"​​配置判断提供者服务是否存在,不存在则触发异常。代码如下:

Boolean c = check;
if (c == null && consumer != null) {
c = consumer.isCheck();
}
if (c == null) {
c = true; // default true
}
if (c && !invoker.isAvailable()) {
// make it possible for consumer to retry later if provider is temporarily unavailable
initialized = false;
throw new IllegalStateException("Failed to check the status of the service " + interfaceName + ". No provider available for the service " + (group == null ? "" : group + "/") + interfaceName + (version == null ? "" : ":" + version) + " from the url " + invoker.getUrl() + " to the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion());
}

5. 小结

在本小节中我们主要学习了 Dubbo 中的3种服务启动检查配置方式,分别从 XML 配置、属性配置、JVM参数等方式进行简单的配置,我们可以总结道是否需要检查依赖服务根据我们具体的业务场景来决定,需要在启动时候就要检查依赖服务是否存储则配置 ​​check="true"​​​否则配置 ​​check="false"​​。

本节课程的重点如下:

  1. 理解 Dubbo 中启动服务依赖检查
  2. 了解什么场景需要依赖检查
  3. 了解怎么配置服务以来检查
  4. 了解了启动依赖检查的实现原理

作者

个人从事金融行业,就职过易极付、思建科技、某网约车平台等重庆一流技术团队,目前就职于某银行负责统一支付系统建设。自身对金融行业有强烈的爱好。同时也实践大数据、数据存储、自动化集成和部署、分布式微服务、响应式编程、人工智能等领域。同时也热衷于技术分享创立公众号和博客站点对知识体系进行分享。