Chinaunix首页 | 论坛 | 博客
  • 博客访问: 562603
  • 博文数量: 104
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1559
  • 用 户 组: 普通用户
  • 注册时间: 2014-08-21 00:58
个人简介

锻炼精神,首先要锻炼肉体

文章分类

全部博文(104)

文章存档

2018年(1)

2016年(1)

2015年(101)

2014年(1)

我的朋友

分类: Java

2015-06-28 17:04:20

我使用 ZooKeeper API 编程主要就是想编写出可以在执行 创建、删除、修改当前系统中正在运行的 ZooKeeper 进程中的路径这些操作的时候 ,
可以通过设定触发事件而在程序中接收到相关的提示信息。
ZooKeeper 除了提供这种应用还有很多其他方面的应用,但是暂时用不上,所以就先不介绍其他的。

而这些提示信息多半是通过用户 implements Watcher 这个接口,并将自定义的操作方法写入到 Watcher 接口中的 process 方法中来实现的。

所以,在这篇文章中,简单的总结一下,ZooKeeper 的 API 中都有支持哪些触发事件,以及如何编写响应这些事件的回调方法。

1. 事件类型介绍
   org.apache.zookeeper.Watcher.Event ;
   1.1 Event.KeeperState.*
   这个事件种类是用来表示当前的客户端连接、是否有访问服务器的权限等的问题的。也就是 client 与 server 之间的事件描述为主体。 
  
AuthFailed
如果当前试图连接 ZooKeeper 的客户端并没有连接权限的话, 就会触发该事件的发生

ConnectedOnly

如果当前 client 连接到一个 ZooKeeper 服务器上之后,只能够, 对其路径进行访问查看,而不能更新节点,或是删除、新增节点的话,
说明该 client 连接到的 ZooKeeper-server 是 只读服务器,一旦连接成功,便会触发 ConnectedOnly 事件发生。

 Disconnected
如果 client 没有连接到任何一个 Zookeeper-server 或者是断开了连接的话, 就会触发该事件的发生。

Expired
 client 与 server 之间的连接是有会话期的,这个会话期的长短通过 ZooKeeper 的构造方法来设定 。
一旦连接的时间超过了 会话期 时间,该会话期将会被设定为过期。

其中,该 client<--> server 之间的连接,还有一些 Watcher 都会作废.过期之后,便会触发 Expired 事件的发生

NoSyncConnected
  过时的 Event
       

SaslAuthenticated
 client 连接到 server 的时候的权限检测,如果权限不符合,便会触发该事件发生

SyncConnected
 一旦 client 向 server 请求连接,server接收,双方连接达成,便会触发这个事件的发生。
该触发事件的响应方法,通常传入到 ZooKeeper 的构造方法中,如果不太清楚,就先记下
这一点,后续的实验将会介绍。


   1.2 Event.EventType.* ; 
   EventType 这个事件种类是用来表示当前监听的Zookeeper 服务器端的指定路径上是否发生了某些变化,是用来监视某个路径所常用的一套事件类型定义。
   也就是说,服务器上所维护的路径的变动是触发这一些列事件的主体。
  
NodeChildrenChanged
如果将路径 /KyLin 设为被监视的路径,那么在该路径下删除,增添子路径, 或者是修改已存在子路径的数据信息的话都会触发该事件的发生、

NodeCreated
如果,路径 /KyLin 已经存在,却还通过 ZooKeeper API 来创建同名的路径,该事件就会被触发。

NodeDeleted
如果,路径 /KyLin 已经存在,并且被设为监视路径,那么一旦有该路径被删除的操作便会触发该事件的发生。

None
通常是服务器和客户端连接创建成功之后胡触发该事件


2. 不同的事件类型测试方法
在这里根据需要仅测试 EventType 中的全部事件,以及 KeeperState.SyncConnected 事件 ;编程环境的搭建可以参看前一篇文档.

在这里我们所使用的 Watcher 便是 ZooKeeper 为编写回调函数的主要入口,Watcher 的实现可以有两种方式:

一种是直接在含有 Watcher 参数的地方写上
new Watcher { 
  @Overrice
   public void process (WatcherEvent e )
  {
   // user defiend execution
  }
}

一种是,创建一个类实现该接口
class App implements Watcher
{
    @Override
     public void process ( WatcherEvent e )
     {
        // user defined execution
     }
}
传入含有 Watcher 参数的地方,需要传入该类 的实例对象

当然还有一种方法,就是类自身 implements Watcher , 但是在类成员方法中需要传入 Watcher 对象,
这个时候传入 this ,即, 类的自身引用即可。

说到了,触发事件和回调函数,就不得不说一下,注册方法,也就是如何把一个路径设定为受监控的路径。
总结一下 ZooKeeper 的 API ,有如下的方法(并不包括 StatCallback 函数,StatCallback 函数在后面会详细介绍)

Stat exists ( String ,Watcher watcher)
这个方法是用来返回给定路径上面节点/znode 的状态的,但这只是这个方法的功能之一,
我们还可以将自定义的 Watcher 实例传入到该方法的第二个参数的中,相当于为该路径的监控埋下了一个触发事件。

在该 Watcher 接口中的 process 方法中写入一系列针对不同事件而触发的相关方法调用。
这样等到调用该 exists  方法的路径上面真的发生了提前注册的事件的话,就会引发一系列的方法。


List<String> getChildren( String path , Watcher) ;
这个方法是用来获取给定路径下面的孩子节点,该方法会将孩子节点的信息封装成 String,并将其存放至一个
List<String> 中,可以通过 for ( String : List ) 的迭代方法遍历。
同时还可以,设置 Watcher, 写入自定义的触发事件。

byte [] getData ( String path , Watcher watcher ,Stat stat )
该方法用于获取指定路径 path 下面的数据信息的,同时也提供设置 Watcher 的方法。
正如我们所知, Watcher 可以处理一部分,这个 getData 方法通常是这样用的,

通过 exists() 设置的 Watcher 触发的事件获知该指定的路径上面发生了变化,于是调用
getData() 方法将变动的数据获取出来,但是,接下来要对其设定的操作在 exists 方法中的 Watcher 接口中并没有实现,
于是,重写创建一个 Watcher 并在 process 中写入另一套专门处理变化数据的方法,通过 getData()
方法将该 Watcher 实例传递进去,开启新的异步分支处理。

这种处理思想类似于,走到某个环节中的某一步之后,前面的处理方法无法使用,但是后面还有其他的分支方法等待处理,
所以,为后续的每个分支写一个解决方法,并将所有的解决方法写入到新创建的 Watcher 中, 然后将 Watcher
实例重新创在到 getData 对应的方法中, 接下来,便会以 getData 为起点开始执行,并根据获取当前走到那个环节
来触发调用刚刚写到 Watcher 实例中的不同方法来处理。

void register ( Watcher watcher ) ;
这个方法是用来为当前的 ZooKeeper 实例重新加载一个新的 Watcher 实例,
通常我们在使用 ZooKeeper的时候, 也就是在它一开始被创建的时候,会为其创建一个 Watcher 实例,
该实例中可以在 process 中这样写:如果 ZooKeeper连接服务器失败应该如何? 如果成功连接应该如何操作、

但是,这个回调方法和我们通常的过程函数也是一样的,为了提高他的重用性以及为了让其正将其灵活性,
通常不会写入过多的分支处理方法入其中的,不然调试起来麻烦,找错误也麻烦。

通常的做法就是,在将程序运行分为不同的环节,在不同的环节有着不同的一组回调跟着,到了某个环节就需要替换掉旧的回调方法,
使用新的回调方法, 而这个 register 也好,上面的 setData 方法也好,都是用来为 ZooKeeper 的程序运行到不同的环节中,替换或者是修改回调函数所用的。

Watcher 就像是 Boost C++ 中的 function<> 一样,用于绑定不同的回调函数,
但是,如果要涉及到参数的和传递的话,function<> 方法就不能用了,就需要借助于实现了动态绑定技术的 bind 系列方法,
而 StatCallback 方法也是一样,它便是回调函数的带参数版本的实现。 这个后续会详细介绍的。







在编写代码之前,应该知道一点就是,ZooKeeper 中提供的 API 有 ZooKeeper 类, 该类所创建的类实例对象,
实质上是 ZooKeeper 的一个客户端句柄,通过该句柄与当前系统中的运行的 ZooKeeper 服务器进行进行连接,
所以, 在运行程序之前,应该保证的便是,当前平台上已经启动了 ZooKeeper 的服务端进程。

同时 , ZooKeeper 创建路径的方式常用的有两种/还有其他的 :
1.永久性存在的路径-----> 也就是说当前的 客户端句柄在服务器端创建了路径之后,带到客户端与服务器端断开连接之后该路径也是会存在的,
2. 暂时性存在的路径 ------> 这种路径,一旦创建该路径的 客户端与服务器端断开连接之后,该路径就会被删除掉。

为了试验简便,我们在这里采用第 2 种创建路径的方法。

其中这些 Watcher 的多种实现方法仅在第一个测试方法实现。


2.1 KeeperState.SyncConnected

2.2 EventType.NodeChildrenChanged

2.3 EventType.NodeCreated

2.4 EventType.NodeDeleted


2.5 EventType.None

    
2.6 AllEvents


end
阅读(2828) | 评论(3) | 转发(0) |
给主人留下些什么吧!~~

夏目玲子2015-07-28 08:36:59

夏目玲子:现在遇到一个 bug 就是,在添加了触发方法之后,其他的事件都可以正常响应,但是唯独 NodeChildrenChanged 总是不被触发。
或许是我设置的参数有问题,如果真的是源码的 bug 的话,只有查看源代码才能找到原因。

现在使用 curator 了,这篇文章没有什么可看的了

回复 | 举报

夏目玲子2015-06-28 22:48:31

夏目玲子:重新编辑乱码,第二个  EventType.NodeChildrenChanged 的测试代码在这个链接下面

http://blog.chinaunix.net/uid-28595538-id-5101271.html

现在遇到一个 bug 就是,在添加了触发方法之后,其他的事件都可以正常响应,但是唯独 NodeChildrenChanged 总是不被触发。
或许是我设置的参数有问题,如果真的是源码的 bug 的话,只有查看源代码才能找到原因。

回复 | 举报

夏目玲子2015-06-28 22:46:36

重新编辑乱码,第二个  EventType.NodeChildrenChanged 的测试代码在这个链接下面

http://blog.chinaunix.net/uid-28595538-id-5101271.html