首页 > 代码库 > Dubbo点滴(5)之服务注册中心
Dubbo点滴(5)之服务注册中心
首先DUBBO本质上是一款RPC框架,不可缺少的2个角色:服务提供者和服务消费者。
已经剖析了服务端暴露端口过程。本文简单说下注册中心。
1.注册中心是什么玩意
这是官网提供的图例
通过图例,可以看出消费者和提供者并不是直接通信的,中间有个第三者,就是注册中心。这种结构,可以实现消费者和提供者两者的依赖,和参数信息的集群化。所以这带来了几个问题。
服务注册
服务发现
服务订阅
服务通知
2. 服务暴露及服务注册过程
《Dubbo点滴(4)之暴露服务解析》已经剖析了dubbo协议具体打开网络端口过程。本节内容会隐去这部分内容。因为一个完整的服务暴露,主要涉及2部分内容,1)打开端口等待消费者连接;2)将服务信息登记到注册中心,以告知消费者可以连接了。
有3点需要说明:
1)首先,根据条件判断会暴露一个injvm本地服务(step 6);
InjvmProtocol协议完成,主要供同一JVM种的消费者调用,提供RPC效率。
2) 为服务暴露一个dubbo服务(step 12),一般为DubboProtocol完成
3)step 12提供的的服务,注册到注册中心(step 13-step 23)。这一步是本文的剖析重点。
3.认识注册中心
该图是DUBBO的总体结构图。重点停留在Resistry层。比较重要的是几个组件
ZookeeperRegistry :负责与zookeeper进行交互
RegistryProtocol :从注册中心获取可用服务,或者将服务注册到zookeeper,然后提供服务或者提供调用代理。
RegistryDirectory :维护着所有可用的远程Invoker或者本地的Invoker。这个类实现了NotifyListner。
NotifyListener :负责RegistryDirectory和ZookeeperRegistry的通信。
FailbackRegistry:继承自Registry,实现了失败重试机制。
4. 注册中心数据模型
流程说明:
服务提供者启动时
向/dubbo/com.foo.BarService/providers目录下写入自己的URL地址。
服务消费者启动时
订阅/dubbo/com.foo.BarService/providers目录下的提供者URL地址。
并向/dubbo/com.foo.BarService/consumers目录下写入自己的URL地址。
监控中心启动时
订阅/dubbo/com.foo.BarService目录下的所有提供者和消费者URL地址。
4.Registry 结构树
ZookeeperRegistry是常见的注册中心实现方案,由ZookeeperRegistryFactory负责构造。
AbstractRegistry这个类主要存储的是已经注册的服务接口,已经订阅的服务接口和已经收到通知的接口的URL,不能直接调用。
public abstract class AbstractRegistry implements Registry { // 本地磁盘缓存,其中特殊的key值.registies记录注册中心列表,其它均为notified服务提供者列表 private final Properties properties = new Properties(); // 文件缓存定时写入 private final ExecutorService registryCacheExecutor = Executors.newFixedThreadPool(1, new NamedThreadFactory("DubboSaveRegistryCache", true)); //是否是同步保存文件 private final boolean syncSaveFile ; private final AtomicLong lastCacheChanged = new AtomicLong(); private final Set<URL> registered = new ConcurrentHashSet<URL>(); private final ConcurrentMap<URL, Set<NotifyListener>> subscribed = new ConcurrentHashMap<URL, Set<NotifyListener>>(); private final ConcurrentMap<URL, Map<String, List<URL>>> notified = new ConcurrentHashMap<URL, Map<String, List<URL>>>(); ... }
FailbackRegistry 继承自AbstractRegistry ,实现了失败重试机制。
public abstract class FailbackRegistry extends AbstractRegistry { // 定时任务执行器 private final ScheduledExecutorService retryExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("DubboRegistryFailedRetryTimer", true)); // 失败重试定时器,定时检查是否有请求失败,如有,无限次重试 private final ScheduledFuture<?> retryFuture; private final Set<URL> failedRegistered = new ConcurrentHashSet<URL>(); private final Set<URL> failedUnregistered = new ConcurrentHashSet<URL>(); private final ConcurrentMap<URL, Set<NotifyListener>> failedSubscribed = new ConcurrentHashMap<URL, Set<NotifyListener>>(); private final ConcurrentMap<URL, Set<NotifyListener>> failedUnsubscribed = new ConcurrentHashMap<URL, Set<NotifyListener>>(); private final ConcurrentMap<URL, Map<NotifyListener, List<URL>>> failedNotified = new ConcurrentHashMap<URL, Map<NotifyListener, List<URL>>>(); ... }
5.服务提供者启动的注册过程
服务提供者启动时 向/dubbo/com.foo.BarService/providers目录下写入自己的URL地址。接下来,找寻下代码执行路径。RegistryProtocol 作为注册中心的核心组件,作为代码的入口,还要明确一点,这是个注册登记过程。
//入口 public class RegistryProtocol implements Protocol { final Registry registry = getRegistry(originInvoker); final URL registedProviderUrl = getRegistedProviderUrl(originInvoker); registry.register(registedProviderUrl); } public abstract class AbstractRegistry implements Registry { public void register(URL url) { if (url == null) { throw new IllegalArgumentException("register url == null"); } if (logger.isInfoEnabled()){ logger.info("Register: " + url); } registered.add(url); } ... } public abstract class FailbackRegistry extends AbstractRegistry { public void register(URL url) { super.register(url); failedRegistered.remove(url); failedUnregistered.remove(url); try { // 向服务器端发送注册请求 doRegister(url); } catch (Exception e) { ... } // 将失败的注册请求记录到失败列表,定时重试 failedRegistered.add(url); } protected abstract void doRegister(URL url); protected abstract void doUnregister(URL url); protected abstract void doSubscribe(URL url, NotifyListener listener); protected abstract void doUnsubscribe(URL url, NotifyListener listener); ... } public class ZookeeperRegistry extends FailbackRegistry { public ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter) { super(url); //如果provider的url是“0.0.0.0”或者在参数中带anyHost=true则抛出异常注册地址不存在 if (url.isAnyHost()) { throw new IllegalStateException("registry address == null"); } //服务分组(默认“dubbo”) String group = url.getParameter(Constants.GROUP_KEY, DEFAULT_ROOT); if (! group.startsWith(Constants.PATH_SEPARATOR)) { group = Constants.PATH_SEPARATOR + group; } //服务分组根地址 this.root = group; zkClient = zookeeperTransporter.connect(url); //添加状态监听器 zkClient.addStateListener(new StateListener() { public void stateChanged(int state) { if (state == RECONNECTED) { try { recover(); } catch (Exception e) { logger.error(e.getMessage(), e); } } } }); } protected void doRegister(URL url) { try { //连接注册中心注册,在zk上创建节点 zkClient.create(toUrlPath(url), url.getParameter(Constants.DYNAMIC_KEY, true)); } catch (Throwable e) { throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e); } } }
6. 注册中心关系类图
重要概念:
ZookeeperRegistry :负责与zookeeper进行交互
RegistryProtocol :从注册中心获取可用服务,或者将服务注册到zookeeper,然后提供服务或者提供调用代理。
RegistryDirectory :维护着所有可用的远程Invoker或者本地的Invoker。这个类实现了NotifyListner。
NotifyListener :负责RegistryDirectory和ZookeeperRegistry的通信。
FailbackRegistry:继承自Registry,实现了失败重试机制。
本文出自 “简单” 博客,请务必保留此出处http://dba10g.blog.51cto.com/764602/1885721
Dubbo点滴(5)之服务注册中心