继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

从源码看zookeeper注册中心的实现

small_925_ant
关注TA
已关注
手记 69
粉丝 6395
获赞 157

motan中的注册中心

注册中心是在很多RPC框架中不可缺少的一部分,最近公司需要将现有系统进行升级,也需要一套注册中心进行对多个执行器进行管理。
今天就先学习一下在开源框架中是如何进行使用的,主要关注zookeeper的实现。

motan 中的consumer和provider

provider作为服务的提供者,在发布后会将自己提供服务的信息、机器IP、端口注册到zk中。
consumer在调用具体服务的时候,会先根据调用服务的信息,去注册中心查询到当前服务被暴露在哪些机器上。然后返回需要的代理类,最
终在通过客户端的负载均衡和高可用的策略进行调用。

我们可以运行motan-demo中的MotanApiExportDemo,然后观察zookeeper,主要代码如下:
 //2-设置接口及实现类
motanDemoService.setInterface(MotanDemoService.class);
motanDemoService.setRef(new MotanDemoServiceImpl());
// 配置服务的group以及版本号
motanDemoService.setGroup("motan-demo-rpc");
motanDemoService.setVersion("1.0");
//3-配置注册中心zk
RegistryConfig registry = new RegistryConfig();
registry.setRegProtocol("zookeeper");
registry.setAddress("192.168.88.129:2181");
motanDemoService.setRegistry(registry);
......
motanDemoService.setExport("motan:8004");

会发现zk下面会多出一个目录
motan
继续看看里面的内容吧:
ls /motan
[motan-demo-rpc]

ls /motan/motan-demo-rpc
[com.weibo.motan.demo.service.MotanDemoService]

ls /motan/motan-demo-rpc/com.weibo.motan.demo.service.MotanDemoService
[server,unavailableServer]

ls /motan/motan-demo-rpc/com.weibo.motan.demo.service.MotanDemoService/server
[10.45.176.187:8002]

到这里我们大体就了解了provider在注册中心中注册了哪些内容:
group+接口类的全名称。

下面我们通过源码来主要看一下客户端是怎么获取所需要调用的服务地址的吧。

深入源码

终于可以看代码了!
直接来到关键点ClusterSupport.init()
//这里是进行服务的订阅,通过zk的watch机制,当服务发生变化,会调用ClusterSupport里面的notify方法进行刷新集群信息
Registry registry = getRegistry(ru);
registry.subscribe(subUrl, this);

这里的subUrl其实就是:
motan://10.45.176.187:0/com.weibo.motan.demo.service.MotanDemoService?group=motan-demo-rpc

然后会走到CommandFailbackRegistry类中:

 @Override
 protected void doSubscribe(URL url, final NotifyListener listener) {
        LoggerUtil.info("CommandFailbackRegistry subscribe. url: " + url.toSimpleString());
        URL urlCopy = url.createCopy();
        CommandServiceManager manager = getCommandServiceManager(urlCopy);
        manager.addNotifyListener(listener);

        subscribeService(urlCopy, manager);
        subscribeCommand(urlCopy, manager);

        List<URL> urls = doDiscover(urlCopy);
        if (urls != null && urls.size() > 0) {
            this.notify(urlCopy, listener, urls);
        }
    }

重点关注subscribeService方法,当选择zookeeper实现的注册中心时,会进入ZookeeperRegistry类的subscribeService方法:

String serverTypePath=ZkUtils.toNodeTypePath(url,ZkNodeType.AVAILABLE_SERVER);
zkClient.subscribeChildChanges(serverTypePath, zkChildListener);

此时的serverTypePath:
/motan/motan-demo-rpc/com.weibo.motan.demo.service.MotanDemoService/server
这不就是provider在注册中心注册的地址吗。
到这里我们就知道了consumer是如何获取服务所在地址的了。
当服务数量发生变化时候,consumer是怎么感知的呢?
看一下在上面方法的subscribeChildChanges 中传入了zkChildListener就了解了:
childChangeListeners.putIfAbsent(serviceListener, new IZkChildListener() {
        //对父节点添加监听子节点变化。
        @Override
        public void handleChildChange(String parentPath, List<String> currentChilds) {
                        System.out.println("服务有变化!!!!!!!!!!");
                        serviceListener.notifyService(url, getUrl(), nodeChildsToUrls(url, parentPath, currentChilds));
                        LoggerUtil.info(String.format("[ZookeeperRegistry] service list change: path=%s, currentChilds=%s", parentPath, currentChilds.toString()));
                    }
            });
这里consumer对serverTypePath进行了监听,如下下面的临时节点有变化就会回调当前的IZkChildListener。
那又是怎么通知给consumer的?
serviceListener.notifyService:

for (NotifyListener notifyListener : notifySet) {
     notifyListener.notify(registry.getUrl(), finalResult);
}

我们只需要找到notifyListener是从哪里来的就可以。在上面的
CommandFailbackRegistry.doSubscribe中有这样一段代码:
manager.addNotifyListener(listener);
notifyListener就是从这里加入的。
而这个listener就是consumer在订阅服务列表时候进行加入的,发现又回到了最开始
ClusterSupport.init()中
registry.subscribe(subUrl, this);
看一下ClusterSupport就明白了:
ClusterSupport<T> implements NotifyListener 

notify方法就在ClusterSupport类中:
public synchronized void notify(URL registryUrl, List<URL> urls)
......
具体代码就不列出了,只要知道这里的urls就是服务列表发生变化时候,回调IZkChildListenerz监听器所获取的所有server的列表。
拿到这个列表就可以刷新之前缓存的server列表了。
然后再继续交给后面的负载均衡loadbalance进行选择一个合适的server地址进行服务的调用。
//刷新最新的服务到cluster
refreshCluster();

总结

作为注册中心ZooKeeper的数据模型简单,就是一棵树.并且拥有Watcher机制,让我们方便的去满足服务订阅的需求。学习了其motan中的使用,相信参考其思路一定可以在自己的项目中来实现一套。
注册中心还有很多种实现,后续会继续学习使用,并且进行比较。
打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP