转载

原 荐 dubbo之zookeeper注册中心

背景

前面分析了使用redis作为注册中心的代码dubbo之redis注册中心

我们来看一下官方最推荐生产环境使用的zookeeper~

ZooKeeper是一个 分布式 的,开放源码的 分布式应用程序 协调服务,是 Google 的Chubby一个 开源 的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。

ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。

分析

作为注册中心我们还是要能够快速无误的获取到服务的上下线信息 对于zookeeper不要太简单

zookeeper提供了watch

Znode 发生变化(Znode 本身的增加,删除,修改,以及子 Znode 的变化)可以通过 Watch 机制通知到客户端。那么要实现 Watch,就必须实现 org.apache.zookeeper.Watcher 接口,并且将实现类的对象传入到可以 Watch 的方法中。Zookeeper 中所有读操作(getData(),getChildren(),exists())都可以设置 Watch 选项。Watch 事件具有 one-time trigger(一次性触发)的特性,如果 Watch 监视的 Znode 有变化,那么就会通知设置该 Watch 的客户端。

这个就是相当方便了~作为服务消费者我们需要做的就是监听到服务提供者的节点 对应的change事件收到即可!

protected void doSubscribe(final URL url, final NotifyListener listener) {
    try {
        if (Constants.ANY_VALUE.equals(url.getServiceInterface())) {
         ****
        } else {
            List<URL> urls = new ArrayList<URL>();
            for (String path : toCategoriesPath(url)) {
                ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.get(url);
                if (listeners == null) {
                    zkListeners.putIfAbsent(url, new ConcurrentHashMap<NotifyListener, ChildListener>());
                    listeners = zkListeners.get(url);
                }
                ChildListener zkListener = listeners.get(listener);
                if (zkListener == null) {
                    listeners.putIfAbsent(listener, new ChildListener() {
                        public void childChanged(String parentPath, List<String> currentChilds) {
                           ZookeeperRegistry.this.notify(url, listener, toUrlsWithEmpty(url, parentPath, currentChilds));
                        }
                    });
                    zkListener = listeners.get(listener);
                }
                zkClient.create(path, false);
                List<String> children = zkClient.addChildListener(path, zkListener);
                if (children != null) {
                   urls.addAll(toUrlsWithEmpty(url, path, children));
                }
            }
            notify(url, listener, urls);
        }
    } catch (Throwable e) {
        throw new RpcException("Failed to subscribe " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
    }
}

我们只需要在对应的节点增加监听即可~

dubbo通过自定义的childListener适配到多个不同的zk客户端~

很明显这样就完成关于服务上下线的监听

我们需要注意的是zkClient创建了节点 其中节点调用了如下方法

zkClient.create(path, false);

这边会创建多个节点 【主要指需要订阅通知的】包括providers  这边的false表示为持久节点

我们来看一下如何注册

protected void doRegister(URL url) {
    try {
       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);
    }
}

这边可以看到会根据是否动态创建对应的节点 一般情况下该节点为临时节点

Ephemeral节点在客户端session结束或超时后自动删除

因此当服务下线或者未正常下线【比如超时 网络分区等】

这样该节点将会被移除掉

因此进行监听节点的将会受到nodechanged事件~从而获得最新的服务列表等

原 荐 dubbo之zookeeper注册中心
原文  https://my.oschina.net/qixiaobo025/blog/2872190
正文到此结束
Loading...