Zookeeper的API调用的同步和异步机制以及watcher机制总结

同步和异步调用

对于zookeeper的所有API调用都提供了正常的同步调用和异步调用两种类型的调用接口,比如zookeeper创建某个目录节点的接口为例:

同步调用接口:

String create(final String path, byte data[], List acl,

           CreateMode createMode)

异步调用接口:

void create(finalString path,bytedata[],List acl,

           CreateMode createMode,  StringCallback cb, Object ctx)

--很明显异步调用接口比同步调用接口多了两个参数StringCallback cb,Object ctx,其中最关键的是参数StringCallbackcb,这是异步调用回调入口的依赖对象。使用例子如下

zk.create(ZNODE_NAME,"mymaster20882".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL, myStringCallBack, "enroll master");

StringCallback myStringCallBack = new StringCallback(){

       

        @Override

    public voidprocessResult(intrc, String path, Object ctx, String name) {

业务代码………………

}

       

};

--很明显是创建了一个匿名的内部类的方式实现的,该匿名类实现了StringCallback接口,并重写了接口的processResult方法,整个异步回调机制类似watcher机制,都是客户端向服务端发送请求后不阻塞客户端线程,继续往后面执行代码,等服务端执行完客户端的请求后再往客户端发送执行结果,客户端通过非阻塞io发现可读事件,并把可读的执行结果写入waitingEvents队列,以便eventThread线程轮询调用相关的StringCallback对象的processResult方法。Zookeeper的watcher机制也是这样的流程,不同的是watcher机制的返回消息的事件类型是watcher,而异步api调用返回的消息事件类型是StringCallback。

虽然两者的实现机制流程是相似的,但是使用上属于不同维度,不冲突,在使用watcher的同时也能使用异步api调用。

 

Watcher监听机制的类型和永久性

Zookeeper的watcher机制分成两大类型:defaultWatcher 和非defaultWatcher

defaultWatcher

其中defaultWatcher是在创建zookeeper对象(也就是客户端) 时传入构造方法。而且所有路径节点的改变都会通知defaultWatcher。

非defaultWatcher

非defaultWatcher分成三类:

dataWatcher,existWatcher,childWatcher

它们是通过下面对应的api来注册watcher的

dataWatcher-> getData()   --注意setData, delete方法是不能注册watcher的

existWatcher-> exists()

childWatcher-> getChildren()

--非defaultWatcher的watcher是一次性的,所有如果需要实现所谓的永久性监控就得在Watcher的回调方法process方法中重新注册watcher

 

注意:其实defaultWatcherdefaultWatcher都是一次性的,所以如果要实现所谓的永久性监控,那就得在watcher的回调中重新注册,其中defaultWatcher的注册有点特别,不需要再明显在api指定watcher对象名,只需要对getData()exists()getChildren()booleanwatch参数设置为true即可。

 

综合上面两个表,我们可以总结出各种写操作可以触发哪些watcher,如下表所示:

 

“/path”

“/path/child”

 

exists

getData

getChildren

exists

getData

getChildren

create(“/path”)

 

 

 

 

delete(“/path”)

 

 

 

setData(“/path”)

 

 

 

 

create(“/path/child”)

 

 

 

delete(“/path/child”)

 

 

setData(“/path/child”)

 

 

 

 

 

 

 

Watcher机制的用例说明

defaultWatcher的用例

1.首先创建watcher对象,使用匿名内部类的方式

Watcher myWatcher= new Watcher(){

 

                     @Override

                     public voidprocess(WatchedEvent event) {

                            // TODOAuto-generated method stub

                            System.out.println(event.getPath()+""+event.getType());

                            try {

                                   zk.exists("/root", true);

                            } catch(KeeperException e) {

                                   // TODOAuto-generated catch block

                                   e.printStackTrace();

                            } catch(InterruptedException e) {

                                   // TODOAuto-generated catch block

                                   e.printStackTrace();

                            }   

                     }

                    

              };

2.在创建zookeeper对象时传入构造方法

zk = newZooKeeper("127.0.0.1:2181", 5000, myWatcher);

 

3.在使用注册watcher的api时,如果选择注册defaultWatcher,那么需要选择参数中带有boolean watch参数的方法。比如

getData(Stringpath, boolean watch, Stat stat)

exists(Stringpath, boolean watch)

getChildren(Stringpath, boolean watch)

并且boolean watch设置为true,比如下面例子:

zk.exists("/root",false); 

zk.setData("/root","mydata".getBytes(), -1);

 

4.如何所谓永久地使defaultWatcher进行watch

可以注意到第一步1中红色内容zk.exists("/root", true);

实际上就是在回调方法中重新注册了defaultWatcher

 

 

非defaultWatcher的用例

非defaultWatcher的使用跟defaultWatcher基本一样,也是第一步创建watcher匿名内部类和watcher对象。不同的是不用第二步,直接到第三步,只是第三步使用的注册api接口跟defaultWatcher不一样,使用的接口比如:

getData(finalString path, Watcher watcher, Stat stat)

exists(finalString path, Watcher watcher)

getChildren(finalString path, Watcher watcher)

第四步如何所谓永久地使用非defaultWatcher进行监控,其实跟上面的4是类似的,在回调方法中重新注册非defaultWatcher

 

 

利用zookeeper进行分布式加锁和master选举问题

所谓的利用zookeeper实现分布式加锁其实就是利用了create接口的并发安全性来实现,所有客户端都去创建临时节点 /distribute_lock 节点,但zookeeper保证最终只有一个客户端成功创建,那个客户端也即拥有了这把锁。

比如:

zk.create(ZNODE_NAME,"mymaster20882".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL, myStringCallBack, "enroll master");

--多个客户端去创建临时节点ZNODE_NAME,但是只有一个能成功。注意CreateMode.EPHEMERAL这表示创建的这个节点是个非永久性的节点,会话消失后就消失。通过异步回调对象myStringCallBack的回调方法获得create的最终状态结果,竞争失败的客户端将进行watcher注册,等到获得锁的客户端会话消失后去再次竞争分布式锁。用这种机制实现分布式加锁和master选举,至于create的服务端的并发安全性有zookeeper自身保证。

 

你可能感兴趣的:(大数据)