zookeeper是著名hadoop的子项目,是一个开源的分布式的协调服务,这个是zk的大致样子
zk可以数据发布订阅、负载均衡、命名服务、分布式协调/通知、集群管理、分布式锁、分布式队列等功能
zk具有一下优点:
- 顺序一致性:
- 从同一个客户端发起的事务请求,最终将会严格按照其发起顺序被应用到zookeeper中
- 原子性:
- 所有事物请求的处理结果在整个集群中所有机器上的应用情况是一致的,即,要么整个集群中所有机器都成功应用了某一事务
- 要么都没有应用,一定不会出现集群中部分机器应用了改事务,另外一部分没有应用的情况。
- 单一视图:
- 无论客户端连接的是哪个zookeeper服务器,其看到的服务端数据模型都是一致的.
- 可靠性:
- 一旦服务端成功的应用了一个事务,并完成对客户端的响应,那么该事务所引起的服务端状态变更将会一直保留下来,
- 除非有另一个事务又对其进行了改变。
- 实时性:
- zookeeper并不是一种强一致性,只能保证顺序一致性和最终一致性,只能称为达到了伪实时性。
zk的数据模型和linux的文件系统非常相似,采用树状结构,而且每个节点都可存储数据,不过可存储的数据很小,是kb级别,而且是存储在内存中.
/---root
|
\----child1
|
\----child2
|
\----child3
|
\----grandson1
|
\----grandson2
zk中的节点有以下几种:
持久化节点(persisrent) 临时节点(ephemeral) 顺序持久化节点(persisrent_sequential) 临时持久化节点 (ephemeral_ephemeral)
当然其中这个临时节点很重要 分布式锁就是通过临时节点来实现的.(后续文章中将重点陈述这个分布式锁的实现很简单的)
zk的底层算法的话这里我不做过多的解释,你们自行百度,他是通过paxos实现的选举和各节点的数据一致性
下面重点来了 没错 就是watcher
我们看下zk的watcher事件有哪些
事件类型:(znode相关)
EventType:NodeCreated //节点创建
EventType:NodeDataChanged //节点的数据变更
EventType:NodeChildrentChanged //子节点下的数据变更
EventType:NodeDeleted //节点被删除
状态类型:(是跟客户端实例相关的)
KeeperState:Disconneced //连接失败
KeeperState:SyncConnected //连接成功
KeeperState:AuthFailed //认证失败
KeeperState:Expired //会话过期
即我们上编代码中写的
/**
* 重写process用来监控watcher事件
* @param watchedEvent
*/
@Override
public void process(WatchedEvent watchedEvent) {
Event.EventType type = watchedEvent.getType();
Event.KeeperState state = watchedEvent.getState();
//是否连接成功
if(Event.KeeperState.SyncConnected==state){
if(Event.EventType.None==type){
System.out.println("成功连接到zk服务器");
//zk连接成功将计数器清零
countDownLatch.countDown();
}
//如果是创建节点事件
else if(Event.EventType.NodeCreated==type){
System.out.println("创建节点成功");
}
//如果节点中的数据被改变
else if(Event.EventType.NodeDataChanged==type){
System.out.println("节点数据发生变化");
}
//如果子节点的数据发生改变
else if(Event.EventType.NodeChildrenChanged==type){
System.out.println("子节点数据发生改变");
}
//节点被删除事件
else if(Event.EventType.NodeDeleted==type){
System.out.println("节点被删除");
}else;
}else if(Event.KeeperState.Disconnected==state){
//连接失败直接退出
return;
}
try {
//阻塞当前线程,直到zk初始化完毕.
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
这个watcher事件只会触发一次,除非当前客户端与服务端交互的时候再次通知需要一个watcher.
那么这个watcher事件有什么用呢,举个例子,我们创建分布式的缓存,将redis地址存入到zookeeper中,但是一旦我们的redis地址发生法改变,此时应用如何得知呢,这个时候就通过watcher事件,进行回调,当节点数据发生变化以后立即通知客户端,吧最新的地址通知应用.
!!!切记一定要注册watcher,这样当节点数据发生改变的时候才会触发watcher事件,而且只会出发一次.
可以注册watcher的方法有
getData、exists、getChildren