个人博客导航页(点击右侧链接即可打开个人博客):大牛带你入门技术栈
Dubbo源码解读 — 注册中心的实现
Dubbo源码解读 — 注册中心的实现 0、概述 1、注册中心的工作流 2、注册中心的数据结构 3、Redis注册源码跟读 4、源码跟读记录的知识点
本源码解读dubbo版本为:2.7.6,今天主要阅读注册中心源码Redis的实现,从Redis实现原理发现,发现两个问题:
1、如果服务宕机,就会造成服务没有广播?
2、Redis的发布订阅通道并不是消息可靠的,如果使用集群,主节点挂了,从节点数据没有同步?
以上两个会导致订阅方不知道服务方已经下线,该如何解决?资料查询需要依赖服务治理中心
0、概述
-
注册中心的作用:
-
动态加入:服务提供者通过注册中心动态把自己暴露给消费者,无需消费者更新配置文件
-
动态发现:一个消费者可以动态地感知新的配置,路由规则和新服务提供者,不需要重启服务
-
动态调整:参数调整,自动更新相关服务节点
-
统一配置:
扫描二维码关注公众号,回复: 9857881 查看本文章
-
-
Dubbo注册中心源码在dubbo-registry模块下:
dubbo-registry-api API和抽象实现类 dubbo-registry-default 基于内存的默认实现 dubbo-registry-multicast dubbo-registry-zookeeper zk实现 dubbo-registry-redis redis实现 dubbo-registry-consul 服务网格实现 dubbo-registry-etcd3 dubbo-registry-nacos nacos实现 dubbo-registry-multiple dubbo-registry-sofa dubbo-registry-eureka
1、注册中心的工作流
2、注册中心的数据结构
-
ZooKeeper
ZK是树形结构的注册中心,节点有持久、持久顺序、临时、临时顺序 【Zk使用场景】
对Dubbo,Zk会创建持久、临时节点,对顺序无要求
-
Redis
Redis使用Key/Map
3、Redis注册源码跟读
-
类RedisRegistry
-
工厂注册
-
RedisRegistryFactory类
4、源码跟读记录的知识点
-
订阅发布的实现
1)Redis 中 key = toCategoryPath(url)即:root+service+type【providers、consumers、routers、configurators】作为key
private String toServicePath(URL url) { return root + url.getServiceInterface(); } private String toCategoryPath(URL url) { return toServicePath(url) + PATH_SEPARATOR + url.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY); }
2)Redis订阅发布机制使用的是过期时间和publish/subscribe通道,启动调度线程池不断刷新过期时间
this.expireFuture = expireExecutor.scheduleWithFixedDelay(() -> { try { deferExpired(); // Extend the expiration time } catch (Throwable t) { // Defensive fault tolerance logger.error("Unexpected exception occur at defer expire time, cause: " + t.getMessage(), t); } }, expirePeriod / 2, expirePeriod / 2, TimeUnit.MILLISECONDS); 核心代码: getRegistered从缓存中获取url,然后组装key,过期后就发布 for (URL url : new HashSet<>(getRegistered())) { if (url.getParameter(DYNAMIC_KEY, true)) { String key = toCategoryPath(url); if (jedis.hset(key, url.toFullString(), String.valueOf(System.currentTimeMillis() + expirePeriod)) == 1) { jedis.publish(key, REGISTER); } } }
-
缓存机制
Dubbo的缓存机制是在AbstractRegistry类中实现的,消费者或服务治理中心会获取注册信息后会在本地做缓存,内存中有一份,也会持久化一份。构造函数中进行的加载
private final ConcurrentMap<URL, Map<String, List<URL>>> notified = new ConcurrentHashMap<>(); 这个是内存中的缓存对象 private File file; 文件缓存对象
-
重试机制
FailbackRegistry类中实现几种注册,订阅,通知失败(五种)时的重试,启动一个定时任务不断尝试。
public FailbackRegistry(URL url) { super(url); this.retryPeriod = url.getParameter(REGISTRY_RETRY_PERIOD_KEY, DEFAULT_REGISTRY_RETRY_PERIOD); // 定时任务 retryTimer = new HashedWheelTimer(new NamedThreadFactory("DubboRegistryRetryTimer", true), retryPeriod, TimeUnit.MILLISECONDS, 128); }
-
设计模式
从源码可以发现,注册中心使用了模板模式(抽象类提取公共方法)和工厂模式,在工厂类中使用了重入锁(ReentrantLock)控制获取不同的注册形式
// Lock the registry access process to ensure a single instance of the registry LOCK.lock(); try { Registry registry = REGISTRIES.get(key); if (registry != null) { return registry; } //create registry by spi/ioc registry = createRegistry(url); if (registry == null) { throw new IllegalStateException("Can not create registry " + url); } REGISTRIES.put(key, registry); return registry; } finally { // Release the lock LOCK.unlock(); }
附Java/C/C++/机器学习/算法与数据结构/前端/安卓/Python/程序员必读/书籍书单大全:
(点击右侧 即可打开个人博客内有干货):技术干货小栈
=====>>①【Java大牛带你入门到进阶之路】<<====
=====>>②【算法数据结构+acm大牛带你入门到进阶之路】<<===
=====>>③【数据库大牛带你入门到进阶之路】<<=====
=====>>④【Web前端大牛带你入门到进阶之路】<<====
=====>>⑤【机器学习和python大牛带你入门到进阶之路】<<====
=====>>⑥【架构师大牛带你入门到进阶之路】<<=====
=====>>⑦【C++大牛带你入门到进阶之路】<<====
=====>>⑧【ios大牛带你入门到进阶之路】<<====
=====>>⑨【Web安全大牛带你入门到进阶之路】<<=====
=====>>⑩【Linux和操作系统大牛带你入门到进阶之路】<<=====天下没有不劳而获的果实,望各位年轻的朋友,想学技术的朋友,在决心扎入技术道路的路上披荆斩棘,把书弄懂了,再去敲代码,把原理弄懂了,再去实践,将会带给你的人生,你的工作,你的未来一个美梦。