您的位置:首页 > 其它

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

2017-09-25 15:53 316 查看
同步和异步调用

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

同步调用接口:

String create(final String
path, byte
data[], List<ACL>
acl,
CreateMode createMode)

异步调用接口:

void create(finalString
path,bytedata[],List<ACL>
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
void
processResult(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

注意:其实defaultWatcher和非defaultWatcher都是一次性的,所以如果要实现所谓的永久性监控,那就得在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自身保证。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐