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