第三章:开始使用zookeeper的API

zookeeper的API围绕zookeeper的句柄而构建,每个句柄代表与zookeeper的一个会话。
已经建立的一个会话如果端口,这会话会转移到另一台zookeeper服务器上 只要会话还存活,这个句柄就有效,zookeeper客户端会保持这个活跃的连接,以保证与zookeeper服务器之间的会话存活。
如果句柄关闭,zookeeper客户端就会告知zookeeper服务器终止会话
如果zookeeper服务器发现客户端已经死掉,就会是这个会话无效
如果客户端之后尝试重新连接zookeeper服务器,使用之前无效会话对应的句柄进行连接,那么zookeeper服务器会通知客户端,这个会话已经失效,使用这个句柄进行的任何操作都会返回错误。
 
创建zookeeper句柄的构造函数:
Zookeeper(String connectString,int sessionTimeout,Watch watcher)
connectString中包含了主机名和zookeeper服务器的端口
sessionTimeout以毫秒为单位,表示zookeeper等待客户端通讯的最长时间。
watcher用于接收会话事件的一个对象,这个对象是我们自己创建的。需要实现Watcher接口。
 
实现一个简单的Watcher
public interface Watcher{
void process(WatchedEvent event);
}
 
public class Master implements Watcher {
Zookeeper zk;
Master(Zookeeper zk){
this.zk=zk;
}
 
void startZk() {
zk = Zookeeper(hostport,15000,this);
}
 
public void process(WatchedEvent event) {
System.out.println(event);
}
 
public static void main(String[] args) {
Master m = new Master();
m.startZk();
 
Thread.sleep(60000);
}
}
 
现在我们启动zookeeper服务器,然后运行Master,之后停止zookeeper服务器,并保持Master运行,你可以看到synchronized事件之后发生了Disconnected事件,当开发者遇到Disconnected事件时,不要重新创建一个新连接,zookeeper客户端库负责为你重新连接服务,当不幸遇到网络问题或者服务器故障时,zookeeper可以处理这些故障问题。
 
请不要尝试去管理zookeeper客户端连接。zookeeper客户端库会监控与zookeeper服务之间的连接,客户度库不仅告诉我们连接发生了问题,还会主动尝试重新建立通讯。
 
为了确保同一时间只有一个主节点进程处于活动状态,可以使用zookeeper实现简单的群首选举算法。所有潜在主节点进程都尝试创建/master节点,但只有一个能成功,这个成功的进程就是主节点。
常量ZooDefs.Ids.OPEN_ACL_UNSAFE为所有人提供了所有权限。
zookeeper可以通过插件式的认证方法提供了每个节点的ACL策略功能。
可以通过以下代码尝试获得主节点权限:
zk.create("/master",
serverId.getBytes(),
OPEN_ACL_UNSAFE,
CreateMode.Ephemeral);
 
使用create方法会抛出两种异常:KeeperException和InterruptedException。我们需要确保我们处理了这两种异常,特别是ConnectionLossException(KeeperException异常的子类)和KeeperException。对于其他异常我们可以忽略继续执行,但是对于这两种异常,create方法可以已经成功了,所哟如果我们作为主节点就需要捕获并处理他们。
ConnectionLossException异常发生于客户端与zookeeper服务器失去连接时,一般常见的原因由于网络原因导致,例如网络分区或者zookeeper服务器故障。当这个异常发生时,客户端并不知道是在zookeeper服务器处理前丢失请求消息,还是在处理后客户端为收到响应消息。
InterruptedException异常源于客户端线程调用了Thread.interrupt,通常这是应为应用程序部分关闭,但还在被其他相关应用的方法使用。从字面看这个异常,进程会中断本地客户端的请求处理的进程,并使该请求处于为之状态。
以上两种请求都会导致正常请求处理过程的中断。
处理ConnectionLossException异常时,在群首选举时,我们需要找到/master节点,如果进程是自己,就开始成为群首角色,可以使用getData(String path,bool watch,Stat stat)代码获得当前/master节点的数据。
 
zookeeper中所有同步调用方法都有对应的异步调用方法。通过异步调用方法,我们可以在单线程中同时进行多个调用,同时也可以简化我们的实现方式。
void create(
String path,
byte[] data,
List<ACL> acl,
CreateMode createMode,
AsynCallback.StringCallback cb,(提供回调方法的对象)
Object ctx(用户指定上下文信息,回调方法调用时传入的对象实例)
)
回调对象实现只有一个方法StringCallback接口:
void processResult(int rc,String path,Object ctx,String name)
rc:返回调用的结果,OK或者与KeeperException异常对应的编码值
path:我们传给create的path值
ctx:我们传给create的上下文参数
name:创建的znode节点名称
调用成功后。path与name的值一样,但是如果采用Create.Sequential模式,这两个参数值就不会相等。
注意:只有一个单独的线程会所有回调函数,如果回调函数阻塞,所有后续回调调用都会阻塞,因此一般不要在回到函数中集中操作或者阻塞操作。
 
zookeeper会严格维护执行顺序,并提供强有力的有序保证,然而,在多线程下还是需要小心面对顺序问题,多线程下,当回调函数中包含重试逻辑的代码时,一些常见的场景都可能导致错误发生,当遇到ConnectingLossException异常而补发一个请求时,新建立的请求可能排序在其他线程中的请求之后,而实际上其他线程中的请求应该在原来请求之后。
posted @ 2019-03-07 01:04  使用D  阅读(351)  评论(0编辑  收藏  举报