前言
使用 Dubbo 做微服务拆分的童鞋,在多人(多个开发)、多职能(开发与测试)协同进行进行项目开发的时候,可能会碰到如下问题:
- 1)开发的本机服务被发布到了测试环境,而本机由于断点调试、代码未经验证的等原因导致服务稳定性较差,这时候被路由到的开发本地的请求,时不时会出现服务不可用的情况,进而影响到测试童鞋的测试效率。
- 2)开发与开发之间也会存在,本地服务互相调用的情况,进而影响开发效率。
接下来,我们将从 Dubbo 注册中心和路由特性出发,来探讨如何解决上述问题。
方案一:开发和测试环境使用不同的注册中心
该方案是最简单彻底地解决问题 1 的方式,可以有效的保障测试环境的稳定性。
但该方案在依赖服务繁杂的情况下,开发环境可能会碰到如下问题:
- A-1)不是所有依赖服务都部署了开发环境,且对应服务维护团队无精力和意愿再维护一套开发环境
- A-2)再新增一套开发环境,有一定 IT 成本。
- A-3)在开发环境,开发之间依然存在本地服务互相调用的情况
我们该如何解决开发环境的上述子问题?
应用多注册中心 preferred 特性
为了解决问题 A-1 和 A-2,我们的思路是:相同接口优先访问在 RegistryDev 中注册的服务,如果 RegistryDev 中不存在该服务,则再尝试在 RegistryTest 中寻找是否有服务注册。
而 Registry preferred 配置(暂未在官方文档列出,但在 dubbo.xsd 内有提示)正好可以实现上述需求,针对上述流程图,示例配置如下:
开发环境 Consumer 端:
<?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:reference id="demoService" check="true"
interface="org.apache.dubbo.demo.DemoService"/>
<dubbo:reference id="greetingService" check="true"
interface="org.apache.dubbo.demo.GreetingService"/>
</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 官网
有几个点要注意下:
- 虽然标签路由在 2.6.6 版本就已经引入,但中间经过一些更改,时可用时不可用,在 >=2.7.9 之后又完全修复。
- 由于 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®ister=false®istry=nacos×tamp=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®ister=false®istry=nacos×tamp=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®ister=false®istry=nacos×tamp=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®ister=false®istry=nacos×tamp=1621303678602"
从 us 值观测,两种配置方式最终的解析结果是一样的。