dubbo源码分析-注册中心

目前官方提供支持的注册中心有四个选项,分别是Multicast 注册中心、zookeeper 注册中心,Redis 注册中心以及Simple 注册中心。
Multicast 注册中心底层依赖的是MulticastSocket。
zookeeper 注册中心是官方推荐使用的,并且dubbo支持服务提供者实现失效踢出就是依据zookeeper的临时节点的特性,dubbo提供了两种zookeeper客户端,分别是zkclient 和curator。生产环境大多数都是选用了zookeeper作为服务的注册中心,因此我们以zookeeper 注册中心作为切入点去分析整个服务的注册订阅流程。

注册中心职能

注册中心是服务治理的前提条件,是服务调用的依据。

服务注册流程

注册入口

在这里插入图片描述
入口是在RegistryProtocol#export()函数内,这个函数内部的doLocalExport()上一章节已经分析过了,然后大概的复习下RegistryProtocol#export()这个函数的具体职能:

  • 远程协议暴露
    • 封装exporter
    • 启动netty
  • 注册中心相关
    • 获取注册中心实例
    • 注册服务
    • 订阅服务,添加监听

具体流程

一、 链接注册中心,如图:在这里插入图片描述

  1. dubbo使用了抽象工厂模式去实例化注册中心,所以关键的部分在于registryFactory#getRegistry(registryUrl), 由spi支持最终会调用ZookeeperRegistryFactory去完成注册中心实例的构造。 ZookeeperRegistryFactory类图:在这里插入图片描述
    registryFactory#getRegistry()函数是由AbstractRegistryFactory实现的,如图:在这里插入图片描述
  2. 就是说在调用ZookeeperRegistryFactory#getRegistry函数时,默认会调用父类(AbstractRegistryFactory)已经实现的getRegistry,这样做的目的是抽取统一的逻辑,以及通过AbstractRegistryFactory去维护注册中心集合的生命周期。AbstractRegistryFactory#getRegistry函数内部,主要实现实例化具体注册中心的逻辑由模板方法createRegistry(url)完成。createRegistry(url)具体实现交给子类,也就是具体注册中心去重写,在这里是由ZookeeperRegistryFactory完成。如图:在这里插入图片描述
  3. ZookeeperRegistryFactory#createRegistry(url)是整个注册中心实例化的核心,通过new ZookeeperRegistry()完成zookeeper注册中心的连接获取,zookeeperRegistryFactory内部维护了一个ZookeeperTransporter扩展点,默认是zkclient,也就是我们上诉说的dubbo提供了两种连接zookeeper的客户端,默认选用zkclient,如图:在这里插入图片描述
  4. 既然作者选择在实例化ZookeeperRegistry的过程中完成zookeeper注册中心的连接,那我们有必要看下ZookeeperRegistry这个类的类图:在这里插入图片描述
    根据这个类图我们可以知道,ZookeeperRegistry是一个具备失败重连的注册中心(FailbackRegistry提供支持);整个初始化过程经过了AbstractRegistry,FailbackRegistry,最后到达ZookeeperRegistry。
  5. AbstractRegistry做的处理:
  • 将注册url保存到AbstractRegistry成员变量registryUrl中
  • 判断是否同步保存注册中心缓存文件,默认异步保存,如果是同步则当前线程处理缓存写入,如果是异步则新起线程处理,如图:在这里插入图片描述
    这里的registryCacheExecutor是一个用Executors创建的守护线程。
  • 将本地注册中心缓存加载到properties中
  • 执行notify
    然后,走到FailbackRegistry的构造方法
  1. FailbackRegistry做的处理很简单,它内部维护了一个定时任务执行器,目的是定时的去处理失败的注册、取消注册、订阅、取消订阅,通知这些动作。在这里插入图片描述

  2. 最后回到ZookeeperRegistry的构造函数在这里插入图片描述
    关键部分是

zkClient = zookeeperTransporter.connect(url);
  1. 这里的zookeeperTransporter是个adpative类,因为我们没有配置使用的zookeeper客户端,所以这里使用默认的zkclient作为客户端去连接,如图:在这里插入图片描述
    所以具体的connect函数将由扩展Zkclient来实现,来到ZkclientZookeeperTransporter,如图:在这里插入图片描述
    可以看出, 具体的连接注册中心的过程也就是实例化ZkclientZookeeperClient的过程,那我们来看下ZkclientZookeeperClient的类图:在这里插入图片描述
  2. 接下来分析ZkclientZookeeperClient实例化的过程(先放图):在这里插入图片描述
  • 将url保存到AbstractZookeeperClient的成员变量
  • 实例化一个ZkClient(org.I0Itec.zkclient下)
  • 订阅zookeeper状态变化事件,并构造一个状态变化监听器,随时改变AbstractZookeeperClient中维护的StateListener的状态
 private final Set<StateListener> stateListeners = new CopyOnWriteArraySet<StateListener>();
  • 完成构造并返回到ZookeeperRegistry的构造函数继续执行
  1. 经历过上诉操作,执行到了这里:在这里插入图片描述
    构造一个StateListener并装入zkClient的Set中,通过上面的分析,我们知道构造的这个StateListener,最终会在zk客户端监听到状态改变事件时触发,而触发之后要做的事情是recover()
  2. recover()是在FailbackRegistry中具体实现的,如图:在这里插入图片描述
    这个函数的流程时:
    • 将AbstractRegistry中维护的registered集合赋值给recoverRegistered(registered是需要向注册中心注册的服务列表,内容如图:)在这里插入图片描述
    • 如果recoverRegistered不为空,将recoverRegistered遍历封装到failedRegistered中(为retry做准备)
    • 将AbstractRegistry中维护的subscribed集合赋值给recoverSubscribed(subscribed可以理解为当前应用订阅服务的集合,他的数据结构是ConcurrentMap<URL, Set>,其中url为订阅的服务地址,Set为注册的服务状态变化监听器集合)
    • 如果recoverSubscribed不为空,将recoverSubscribed遍历封装到failedSubscribed中(为retry做准备)
  3. 到这里createRegistry(url);这块逻辑就算是走完了,接下来将获取到的注册中心维护起来,如图:在这里插入图片描述
  4. 目前为止,RegistryProtocol#export中的getRegistry(originInvoker)(获取注册中心实例)已经完结,如图:在这里插入图片描述
    那么接下来我们关注
registry.register(registedProviderUrl);

这块是注册服务的逻辑。

  1. register()是由FailbackRegistry提供支持,如图:在这里插入图片描述
    这里处理一些公共的逻辑,然后具体的Register是由子类提供的doRegister(url)实现的(模板方法模式)
  2. 具体实现是ZookeeperRegistry#doRegister,如图:在这里插入图片描述
    zkClient.create()调用的是AbstractZookeeperClient#create(),如图:在这里插入图片描述
    判断ephemeral,从而决定是创建临时节点还是持久节点(依据zookeeper特性),同样,具体实现交由子类(具体的zk客户端)实现createEphemeral和createPersistent去创建(又是模板方法)。
  3. 走到ZkclientZookeeperClient#createEphemeral函数(因为dubbo默认zk客户端是Zkclient,如果需要Curator,需要手动配合),如图:在这里插入图片描述
    ZkclientZookeeperClient内部维护了一个ZkClient(org.I0Itec.zkclient),调用执行创建节点都是由内部的ZkClient的api完成的:
client.createEphemeral(path);

走到这里服务注册的逻辑就算是走完了。
再上一张图定下位:在这里插入图片描述

  1. 接下来就到了 订阅的逻辑,同注册一样,订阅操作也是交由FailbackRegistry处理:在这里插入图片描述
  2. 走到ZookeeperRegistry#doSubscribe具体执行订阅逻辑:
    在这里插入图片描述
  • 添加一个节点变化监听器,在订阅节点发生变化时触发FailbackRegistry#notify,从而实现本地缓存文件的更新以及通知到RegistryProtocol.OverrideListener#notify(),重新生成invoker可执行对象
  • 创建一个持久化节点
  • zkClient.addChildListener(path, zkListener);这块逻辑里面实现具体的zk客户端的订阅操作
  • 订阅完结后,触发一次notify(同上)
  1. 流程完结。

服务暴露总结

服务暴露,涉及到的流程及内容有exporter的暴露,netty的启动,注册中心(本例是zookeeper)的连接、注册以及订阅。在获取注册中心实例的过程中,采用的是工厂方法模式,而在具体的注册、订阅动作中又大量用到了模板方法,对逻辑做了一定的封装提取。

原理图集

依赖关系图

###
来源于官方

服务暴露时序图

  鉴于本人才疏学浅,谈到的内容若有不对的地方烦请告知~也期望与大家一起交流共同进步。

dubbo中封装的zookeeper相关类图

在这里插入图片描述
来源于该篇博客

zookeeper订阅流程图

在这里插入图片描述
来源于肥朝简书


  谈到的内容若有不对的地方烦请告知~也期望与大家一起交流共同进步。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值