Dubbo源码解读—注册中心的实现

编程

本源码解读dubbo版本为:2.7.6,今天主要阅读注册中心源码Redis的实现,从Redis实现原理发现,发现两个问题:

1、如果服务宕机,就会造成服务没有广播?

2、Redis的发布订阅通道并不是消息可靠的,如果使用集群,主节点挂了,从节点数据没有同步?

以上两个会导致订阅方不知道服务方已经下线,该如何解决?资料查询需要依赖服务治理中心

0、概述

  • 注册中心的作用:

    • 动态加入:服务提供者通过注册中心动态把自己暴露给消费者,无需消费者更新配置文件

    • 动态发现:一个消费者可以动态地感知新的配置,路由规则和新服务提供者,不需要重启服务

    • 动态调整:参数调整,自动更新相关服务节点

    • 统一配置:

  • 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、注册中心的工作流

  • Dubbo中文官网

 

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();

    }

读取源码不易,其读其珍惜 2020-03-14

以上是 Dubbo源码解读—注册中心的实现 的全部内容, 来源链接: utcz.com/z/514403.html

回到顶部