这个Dubbo注册中心扩展,有点意思

今天想和大家聊聊Dubbo源码中实现的一个注册中心扩展。它很特殊,也帮我解决了一个困扰已久的问题,刚刚在生产中用了,效果很好,迫不及待想分享给大家。

Dubbo的扩展性非常灵活,可以无侵入源码加载自定义扩展。能扩展协议、序列化方式、注册中心、线程池、过滤器、负载均衡策略、路由策略、动态代理等等,甚至「扩展本身」也可以扩展。

在介绍今天的这个注册中心扩展之前,先抛出一个问题,大家思考一下。

如何低成本迁移注册中心?

有时出于各种目的需要迁移Dubbo的注册中心,或因为觉得Nacos比较香,想从Zookeeper迁移到Nacos,或因前段时间曝出Consul禁止在中国境内使用。

迁移注册中心的方案大致有两种:

  • 方案一:使用Dubbo提供的多注册中心能力,Provider先进行双注册,Consumer逐步迁移消费新注册中心,最后下线老注册中心。该方案的缺点是修改时有上下游依赖关系。

  • 方案二:使用一个同步工具把老注册中心的数据同步到新注册中心,Consumer逐步迁移到新注册中心,最后下线老注册中心。同步工具有开源的Nacos-sync,我之前的文章《zookeeper到nacos的迁移实践》就提到了这个方案。这个方案的缺点是架构变得复杂,需要解决同步数据的顺序性、一致性、同步组件的高可用等问题。

Nacos-sync 参考 https://github.com/nacos-group/nacos-sync

我们从「业务方成本」和「基础架构成本」两个角度考虑一下这两个方案:

业务方成本我们以每次业务方修改并上线代码为1个单位,基础架构成本以增加一个新服务端组件为2个单位,从复杂度上来说基础架构成本远远高于业务方修改并上线代码,但这里我们认为只是2倍关系,做过基础组件开发的同学肯定感同身受,推动别人改代码比自己埋头写代码要难。

我们统计下上述方案中,迁移一对Consumer和Provider总共需要的成本是多少:

  • 方案一:Provider双注册+1;Consumer消费新注册中心+1;Provider下线旧注册中心+1;总成本为3
  • 方案二:同步组件+2;Consumer消费新注册中心+1;Provider下线旧注册中心+1;总成本为4

有没有成本更低的方案?

首先我们不考虑引入同步组件,其次Provider和Consumer能否不修改就能解决?我觉得理论上肯定可以解决,因为Java的字节码是可以动态修改的,肯定能达到这个目的,但这样的复杂度和风险会非常高。

退一步能否每个应用只修改发布一次就完成迁移?

Dubbo配置多注册中心可以参考这篇文章《几个你不知道的dubbo注册中心细节》,你会发现多注册中心是通过配置文件配置的,如下

dubbo.registries.zk1.address=zookeeper://127.0.0.1:2181
dubbo.registries.zk2.address=zookeeper://127.0.0.1:2182

只修改一次代码,就必须把这个配置变成动态的,有点难,但不是做不到,可在应用启动时远程加载配置,或者采取替换配置文件的方式来达到目的。

但这只解决了部分问题,还有两个问题需要解决:

  • Dubbo注册、订阅都发生在应用启动时,应用启动后就没法修改了。也不是完全不能,如果采用了api的方式接入Dubbo可以通过改代码来实现,但几乎这种方式不会被采用;
  • Dubbo消费没法动态切换,多注册中心消费时,Dubbo默认的行为是挑第一个可用的注册中心进行调用,无法主动地进行切换;如果实现了主动切换还有个好处是稳定性提高了很多,万一新注册中心出现问题还可以及时切回去。

这里针对第二点的消费逻辑做一点简单说明,老版本(<2.7.5)逻辑比较简单粗暴,代码位于RegistryAwareClusterInvoker

  1. 挑选第一个可用的注册中心进行调用

新版本(>=2.7.5)则稍微丰富一点,代码位于ZoneAwareClusterInvoker

  1. 挑选一个可用且带preferred偏好配置的注册中心进行调用,注意这个偏好配置不同版本key还不一样,有点坑
  2. 如果都不符合1,则挑选同一个分区且可用的注册中心进行调用,分区也是通过参数配置,这个主要是为了跨机房的就近访问
  3. 如果1、2都不符合,通过一个负载均衡算法挑选出一个可用的注册中心进行调用
  4. 如果1、2、3都不合法,则挑选一个可用的注册中心
  5. 如果上述都不符合,则使用第一个注册中心进行调用

可以看出新版本功能很丰富,但它是有版本要求的,而且控制的key也变来变去,甚至去搜一下也有Bug存在,所以如果是单一稳定的高版本是可以通过这个来做,但大部分还是达不到这个要求。

很长一段时间以来,我都没有想到一个好的办法来解决这个问题,甚至我们公司内部有直接修改Dubbo源码来实现动态切换消费的能力,但这种入侵修改无法持续,直到有一天浏览Dubbo源码时,无意间看到了MultipleRegistry,仿佛发现了新大陆,用醍醐灌顶来形容一点不为过。

MultipleRegistry,有点意思!

MultipleRegistry是Dubbo 2.7.2引入的一个注册中心扩展,注册中心扩展圈起来,要考!意味着这个扩展可以在任何>=2.7.0版本上运行,稍微改改也能在2.7以下的版本使用

这究竟是个什么注册中心的扩展呢?

实际上这个扩展并不是一个实际的注册中心的扩展,而是一个包装,它本身不提供服务注册发现的能力,它只是把其他注册中心聚合起来的一个空壳。

为什么这个「空壳」这么厉害呢?下面我们就来分析分析源码。

由于刚好手上有3.0.0版本的源码,所以接下来的源码分析基于Dubbo 3.0.0版本,也不用担心版本问题,这个扩展自从2.7.2引入之后几乎没有大的改动,只有Bugfix,所以什么版本基本都差不多。只分析接口级服务发现,应用级的暂时不分析,原理类似。

不过在讲源码之前,还得说说Dubbo注册中心插件的运行原理,否则源码可能看不懂,我们以开发一个注册中心扩展为例:

  1. Dubbo注册中心扩展需实现RegistryService和RegistryFactory接口
public interface RegistryService {
   

    void register(URL url);

    void unregister(URL url);

    void subscribe(URL url, NotifyListener listener);

    void unsubscribe(URL url, NotifyListener listener);

    
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值