前言

使用 Dubbo 做微服务拆分的童鞋,在多人(多个开发)、多职能(开发与测试)协同进行进行项目开发的时候,可能会碰到如下问题:

  • 1)开发的本机服务被发布到了测试环境,而本机由于断点调试、代码未经验证的等原因导致服务稳定性较差,这时候被路由到的开发本地的请求,时不时会出现服务不可用的情况,进而影响到测试童鞋的测试效率。
  • 2)开发与开发之间也会存在,本地服务互相调用的情况,进而影响开发效率。

接下来,我们将从 Dubbo 注册中心和路由特性出发,来探讨如何解决上述问题。

方案一:开发和测试环境使用不同的注册中心

该方案是最简单彻底地解决问题 1 的方式,可以有效的保障测试环境的稳定性。

但该方案在依赖服务繁杂的情况下,开发环境可能会碰到如下问题:

  • A-1)不是所有依赖服务都部署了开发环境,且对应服务维护团队无精力和意愿再维护一套开发环境
  • A-2)再新增一套开发环境,有一定 IT 成本。
  • A-3)在开发环境,开发之间依然存在本地服务互相调用的情况

我们该如何解决开发环境的上述子问题?

应用多注册中心 preferred 特性

为了解决问题 A-1 和 A-2,我们的思路是:相同接口优先访问在 RegistryDev 中注册的服务,如果 RegistryDev 中不存在该服务,则再尝试在 RegistryTest 中寻找是否有服务注册。

image.png

而 Registry preferred 配置(暂未在官方文档列出,但在 dubbo.xsd 内有提示)正好可以实现上述需求,针对上述流程图,示例配置如下:

开发环境 Consumer 端:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
  4. xmlns="http://www.springframework.org/schema/beans"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
  6. http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
  7. <!-- 开发环境 Provier 和 Consumer 端的注册中心配置相同 -->
  8. <dubbo:registry address="${RegistryDev}" preferred="true" register="true"/>
  9. <dubbo:registry address="${RegistryStable}" register="false"/>
  10. <dubbo:reference id="demoService" check="true"
  11. interface="org.apache.dubbo.demo.DemoService"/>
  12. <dubbo:reference id="greetingService" check="true"
  13. interface="org.apache.dubbo.demo.GreetingService"/>
  14. </beans>

开发环境 Provider 端:

<?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">

    <!-- 开发环境 Provier 和 Consumer 端的注册中心配置相同 -->
    <dubbo:registry address="${RegistryDev}" preferred="true" register="true"/>
    <dubbo:registry address="${RegistryStable}" register="false"/>

    <dubbo:protocol name="dubbo" port="-1"/>

    <bean id="greetingService" class="org.apache.dubbo.demo.provider.GreetingServiceV2Impl"/>

    <dubbo:service interface="org.apache.dubbo.demo.GreetingService" timeout="5000" ref="greetingService"/>
</beans>

关于 A-3 的解决思路是:开发本地可以自己启动一个注册中心,实践成本不是很高。

前方有坑,注意 Dubbo 版本

在 Dubbo <= 2.7.11 版本中 preferred="true" 参数解析是有错误的,具体可看:Dubbo#7788
在新版本发行之前,我们可以通过 address URL 入参的方式来进行参数设置,例如

<dubbo:registry address="zookeeper://127.0.0.1:2181?registry.preferred=true"/>

方案二:同一注册中心下使用标签路由

可直接参阅官方文档:标签路由|Dubbo 官网
有几个点要注意下:

  1. 虽然标签路由在 2.6.6 版本就已经引入,但中间经过一些更改,时可用时不可用,在 >=2.7.9 之后又完全修复。
  2. 由于 RpcContext 在每次请求完成后都会清楚,所以 consumer tag 需要每次请求都设置。一般通过 servlet 过滤器(在 web 环境下),或者定制的 SPI 过滤器设置 requestTag。

附录

1)竖线分隔的 Address 和配置多个 dubbo:registry 有区别吗?

配置中心配置会由 ConfigValidationUtils.loadRegistries 函数进行解析

// file => org/apache/dubbo/config/ReferenceConfig.java:353
List<URL> us = ConfigValidationUtils.loadRegistries(this, false);

竖线分隔
XML 配置

<dubbo:registry id="registryConsumer" address="nacos://127.0.0.1:8849?namingCacheRegistryDir=d8849|nacos://127.0.0.1:8848?namingCacheRegistryDir=d8848" register="false"/>

最终 us 值:

0 = {URL@4285} "registry://127.0.0.1:8849/org.apache.dubbo.registry.RegistryService?application=demo-consumer&dubbo=2.0.2&enable-auto-migration=true&enable.auto.migration=true&id=registryConsumer&mapping-type=metadata&mapping.type=metadata&namingCacheRegistryDir=d8849&pid=8135&qos.port=33333&register=false&registry=nacos&timestamp=1621303280963"
1 = {URL@4286} "registry://127.0.0.1:8848/org.apache.dubbo.registry.RegistryService?application=demo-consumer&dubbo=2.0.2&enable-auto-migration=true&enable.auto.migration=true&id=registryConsumer&mapping-type=metadata&mapping.type=metadata&namingCacheRegistryDir=d8848&pid=8135&qos.port=33333&register=false&registry=nacos&timestamp=1621303280963"

多 dubbo:registry
XML 配置

<dubbo:registry address="nacos://127.0.0.1:8849?namingCacheRegistryDir=d8849" register="false"/>
<dubbo:registry address="nacos://127.0.0.1:8848?namingCacheRegistryDir=d8848" register="false"/>

最终 us 值:

0 = {URL@4132} "registry://127.0.0.1:8849/org.apache.dubbo.registry.RegistryService?application=demo-consumer&dubbo=2.0.2&enable-auto-migration=true&enable.auto.migration=true&id=org.apache.dubbo.config.RegistryConfig&mapping-type=metadata&mapping.type=metadata&namingCacheRegistryDir=d8849&pid=8520&qos.port=33333&register=false&registry=nacos&timestamp=1621303678602"
1 = {URL@4133} "registry://127.0.0.1:8848/org.apache.dubbo.registry.RegistryService?application=demo-consumer&dubbo=2.0.2&enable-auto-migration=true&enable.auto.migration=true&id=org.apache.dubbo.config.RegistryConfig2&mapping-type=metadata&mapping.type=metadata&namingCacheRegistryDir=d8848&pid=8520&qos.port=33333&register=false&registry=nacos&timestamp=1621303678602"

从 us 值观测,两种配置方式最终的解析结果是一样的。