注册中心作用

开篇首先想思考一个问题,没有注册中心 Dubbo 还能玩下去吗?

当然可以,只要知道服务提供者地址相关信息,消费者配置之后就可以调用。如果只有几个服务,这么玩当然没问题。但是生产服务动辄成千上百,如果每个服务都需要手写配置信息,想象一下是多么麻烦。

好吧,如果上面的问题都不是事的话,试想一下如果一个服务提供者在运行过程中宕机,消费者怎么办?消费者不知情,所以它还会不断把请求发往服务提供者,然后不断失败。这个时候唯一的办法就是修改服务地址信息,然后重启服务。

可以看到如果没有注册中心,分布式环境中服务查找发现将会非常麻烦,一切需要手工配置,无法完成自动化。所以这里就需要一个第三者,协调服务提供者与消费者之间关系,这就是注册中心。

注册中心主要作用如下:

  1. 动态加入,服务提供者通过注册中心动态的把自己暴露给消费者,无需消费者逐个更新配置文件。
  2. 动态发现服务,消费者可以动态发现新的服务,无需重启生效。
  3. 统一配置,避免本地配置导致每个服务配置不一致。
  4. 动态调整,注册中心支持参数动态调整,新参数自动更新到所有相关的服务节点。
  5. 统一管理,依靠注册中心数据,可以统一管理配置服务节点。

注册中心工作流程

注册中心工作流程总体比较简单,流程图大致如下:

主要工作流程可以分为如下几步:

  1. 服务提供者启动之后,会将服务注册到注册中心。
  2. 消费者启动之后主动订阅注册中心上提供者服务,从而获取到当前所有可用服务,同时留下一个回调函数。
  3. 若服务提供者新增或下线,注册中心将通过第二步的注册的回调函数通知消费者。
  4. dubbo-admin(服务治理中心)将会会订阅服务提供者以及消费者,从而可以在控制台管理所有服务提供者以及消费者。

Dubbo 之前版本主要可以使用 ZooKeeper,Redis 作为注册中心 ,而随着 Dubbo 版本不断更新,目前还支持 nacos,consul,etcd 等做为注册中心。

Dubbo 注册中心核心源码

ps: 以下源码基于 dubbo 2.7.3 版本

注册中心实现使用模板模式,源码位于 dubbo-registry 模块,类关系如下图:

最上层的 RegistryService 接口定义了核心方法,分别为注册,取消注册,订阅,取消订阅以及查询。

中间层抽象类主要实现通用逻辑,如:AbstractRegistry 实现缓存机制,FailbackRegistry 实现失败重试功能。

底层 ZookeeperRegistry等为具体实现类,实现与 ZooKeeper 等注册中心交互的逻辑。

接下去我们具体分析 AbstractRegistryFailbackRegistry 逻辑。

AbstractRegistry 缓存实现的原理

如果每次服务调用都需要调用注册中心实时查询可用服务列表,不但会让注册中心承受巨大的流量压力,还会产生额外的网络请求,导致系统性能下降。

其次注册中心需要非强依赖,其宕机不能影响正常的服务调用。

基于以上几点,注册中心模块在 AbstractRegistry 类中实现通用的缓存机制。这里的缓存可以分为两类,内存服务缓存以及磁盘文件缓存。

内存服务缓存

内存服务缓存很好理解也最容易实现,AbstractRegistry使用一个 ConcurrentMap保存相关信息。

 private final ConcurrentMap<URL, Map<String, List<URL>>> notified = new ConcurrentHashMap<>();

这个集合中 key 为消费者的 URL,而 value 为一个 Map 集合。这个内层 Map 集合使用服务目录作为 key,分别为 providers,routers,configurators,consumers 四类,value 则是对应服务列表集合。

磁盘文件缓存

由于服务重启就会导致内存缓存消失,所以额外增加磁盘文件缓存。

文件缓存默认位置位于 ${user.home}/.dubbo/文件夹,文件名为dubbo-registry-${application.name}-${register_address}.cache。可以设置 dubbo.registry.file 配置信息从而修改默认配置,实现源码如下:

String filename = url.getParameter(Constants.FILE_KEY, System.getProperty("user.home") + "/.dubbo/dubbo-registry-" + url.getParameter(Constants.APPLICATION_KEY) + "-" + url.getAddress() + ".cache");

ps: ${application.name} 取自 dubbo.application.name 信息,${register_address} 取值注册中心地址信息。缓存文件完整名称为:`C:Usersxxx/.dubbo/dubbo-registry-dubbo-auto-configure-consumer-sample-127.0.0.1:2181.cache`

缓存文件内容使用 properties 配置文件格式,即 key=value 格式。key为服务接口名称,value 为服务列表,由于服务可能存在多个,将会使用空格分隔。

缓存文件的加载

dubbo 程序初始化的时候,AbstractRegistry 构造函数将会从本地磁盘文件中将数据读取到 Properties 对象实例中,后续都将会先写入 Properties,最后再将里面信息再写入文件。

缓存初始化的源码为下图。

缓存文件的保存与更新

缓存文件将会通过 AbstractRegistry#notify 方法保存或更新。客户端第一次订阅服务获取的全量数据,或者后续回调中获取到新数据,都将会调用 AbstractRegistry#notify 方法,用来更新内存缓存以及文件缓存。

notify 方法源码如下图:

在保存文件缓存方法中,首先把根据 URL 取出的数据,拼接成字符串,然后写入上面提到过的 properties 对象中,最后输出到文件中。

这里可以选择两种保存方式,同步或异步。由于 notify 可能被多次调用,为了提高系统能,系统默认使用异步方式保存。

saveProperties 方法源码如下:

doSaveProperties 方法最终将会将信息写入缓存。考虑到保存方法可能会被多个线程同时调用,这里使用 CAS 方法,首先比较版本大小,若小于,代表有新线程正在写入信息,本次更新直接丢弃。

其次考虑到多个 dubbo 应用可能共用一份缓存文件,所以这里使用文件排他锁当做分布式锁,防止多个应用并发操作同一份文件。

一旦文件写入异常或者获取锁失败,保存操作将会不断重试,直到超过最大次数。

ps: dubbo 2.7.2 之前重试没有设置最大次数,如果文件没有权限保存,保存将会一直失败,异步线程将会陷入死循环。

doSaveProperties 方法源码如下:

FailbackRegistry 重试机制

FailbackRegistry 继承 AbstractRegistry,实现了 registersubscribe等通用法,并增加 doRegisterdoSubscribe 等模板方法,交由子类实现。

如果 doRegister 等模板方法发生异常,会将失败任务放入集合,然后定时再次调用模板方法。

FailbackRegistry 失败重试集合分别为:

subscribe 方法为例,这里将会调用这些 doSubscribe 的模板方法。如果发生异常将会读取缓存文件中内容,然后加载服务。最后新建异步定时任务加入重试集合中,然后由定时器去重试这些任务。

FailbackRegistry#subscribe 方法源码:

addFailedSubscribed 中将会新建定时任务,然后交由定时器执行。定时任务默认最大重试次数为 3 次,调用时间间隔默认为 5 s。

addFailedSubscribed 源码如下:

其他失败重试任务都比较类似,全都继承自 AbstractRetryTask 父类,类关系如下图。

总结

本文主要讲述注册中心作用,工作流程,通用缓存机制以及失败重试机制。从中可以学到模板模式,以及多线程并发技巧。

这里没有涉及到具体注册中心实现,由于目前最主要使用 ZooKeeper 作为注册中心,所以下篇将会聊聊 ZooKeeper 注册中心原理,敬请期待。

帮助书籍

『深入理解 Apache Dubbo 与实战』

如果有人问你 Dubbo 中注册中心工作原理,就把这篇文章给他相关推荐

  1. 有人问你如何掌握隐含狄利克雷分布(LDA),把这篇文章甩给他

    作者 | 玉龍 一.简介 隐含狄利克雷分布(Latent Dirichlet Allocation,简称LDA)是由 David M. Blei.Andrew Y. Ng.Michael I. Jor ...

  2. 微服务 注册中心的作用_微服务架构Dubbo之注册中心(Zookeeper)

    注册中心简介 在微服务架构中,注册中心是核心的基础服务之一.在微服务架构流行之前,注册中心就已经开始出现在分布式架构的系统中.Dubbo是一个在国内比较流行的分布式框架,被大量的中小型互联网公司所采用 ...

  3. Dubbo学习记录(八) -- Spring整合Dubbo中@Reference注解解析原理

    Spring整合Dubbo中@Reference注解解析原理 @Reference: 可以用在属性或者方法, 意味着需要引用某个Dubbo服务, 那么Dubbo整合Spring后, 我很好奇怎么把这个 ...

  4. java执行sql文件_面试官问你MyBatis SQL是如何执行的?把这篇文章甩给他

    初识 MyBatis MyBatis 是第一个支持自定义 SQL.存储过程和高级映射的类持久框架.MyBatis 消除了大部分 JDBC 的样板代码.手动设置参数以及检索结果.MyBatis 能够支持 ...

  5. 面试官问你B树和B 树,就把这篇文章丢给他

    原文链接:面试官问你B树和B 树,就把这篇文章丢给他 在看这篇文章之前,我们回顾一下前面的几篇关于MySQL的文章,应该对你读下面的文章有所帮助. InnoDB与MyISAM等存储引擎对比 面试官问你 ...

  6. 【电气专业知识问答】问:高压断路器失灵保护的工作原理是什么?

    [电气专业知识问答] 问:高压断路器失灵保护的工作原理是什么? 答:断路器失灵保护是指,当电力系统发生故障时,故障元件的保护正确动作发出断路器跳闸脉冲后,断路器拒绝动作时,能以较短的时限跳开同一母线上 ...

  7. java中session的作用_java中session的工作原理是什么?和Cookies有何区别?

    现在大家学习的东西和以前大不相同了,越来越多的人倾向于去学习高新技术以获得更好的发展.java是很多人的第一选择.java中的知识还是很多的,今天就来为大家介绍一下. 首先来说一下java中sessi ...

  8. HTML中的图片如何自适应屏幕?这篇文章有图片的自适应用法介绍

    首先我们看看HTML中的图片是如何自适应屏幕的: 让图片自适应屏幕大小最简单的方法,保证管用,你把那个图片写在div里面的背景里,也就是background:url(../img/1.jpg) cen ...

  9. Linux中LVM的工作原理是什么?优缺点有哪些?

    在Linux操作系统中,LVM全称Logical Volume Manager,中文意思为逻辑卷管理.之前文章为大家介绍过什么是LVM.LVM名词解释.LVM写入模式等内容,本篇文章为大家介绍一下LV ...

  10. 【DL】图像去噪中的patch size是什么(1篇文章链接和1段代码)

    图像去噪中的patch size是什么(1篇文章链接和1段代码) 写在前面,因为自己不做图像相关的研究,所以具体内容也不敢妄加总结,自己感觉貌似就是将一整张图分成一块一块的进行处理,每个块之间可以重叠 ...

最新文章

  1. hibernate jpa_JPAHibernate替代方案。 如果JPA或Hibernate对于我的项目而言不够好,该怎么办?...
  2. React开发(224):ant design label绑定值
  3. 说一下朗数可视化快速开发平台
  4. shell的算术运算
  5. 2014 Louis Vuitton 40769 apricot NevadaJack Nicklaus
  6. 黑客们成功地在土豆上安装了Linux!
  7. java核心技术卷1 所有示例代码
  8. php微信开发视频教程_PHP微信开发视频资源推荐
  9. 微分方程模型_天生一对,硬核微分方程与深度学习的「联姻」之路
  10. [JAVA毕业设计]高铁在线购票系统源码获取和系统演示
  11. tar 打包解压参数详解
  12. 凯立德导航android历史版本,凯立德导航升级2020版
  13. 这是?国内跨境电商降本增收营销神器
  14. 计算机桌面设置怎么还原,怎么把电脑桌面还原
  15. VR虚拟现实培训解决方案
  16. MySql数据库-58沈剑 架构师之路
  17. [机器学习]随机森林源码(python)
  18. [ 重 新 预 习 ] Node.js搭建服务
  19. Datawhale 知识图谱组队学习之Task 4 用户输入->知识库的查询语句
  20. python画小猪_Python画小猪佩奇

热门文章

  1. RACCommand
  2. ExtJs xtype一览(转存)
  3. 不足百行代码 实体数组转DataTable通用类
  4. 使用SQL的全文搜索功能构建 Web 搜索应用程序
  5. spark 添加依赖_单机用python写spark处理20G的数据
  6. java clob内存溢出_java - 从JSON创建CLOB属性 - 堆栈内存溢出
  7. 拓端tecdat|R语言中的prophet预测时间序列数据模型
  8. PAT题目中用到的一些C++便捷函数记录
  9. css基础知识汇总5
  10. jbpm hibernate.cfg.xml 连接mysql配置_hibernate.cfg.xml文件连接mySql、Oracle、SqlServer配置...