ZooKeeper API使用 I 创建会话

客户端可以通过创建一个 Zookeeper(org.apache.zookeeper.ZooKeeper)实例来连接 ZooKeeper 服务器。ZooKeeper 的4种构造方法如下。

ZooKeeper的构造方法:

ZooKeeper(String connectString, int sessionTimeout, Watcher watcher);
ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, boolean canBeReadOnly);
ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, long sessionId, byte[] sessionPasswd);
ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, long sessionId, byte[] sessionPasswd, boolean canBeReadOnly);

使用任意一个构造方法都可以顺利完成与 ZooKeeper 服务器的会话(Session)创建,下面列出了对每个参数的说明:

参数名 说明
connectString        指定 ZooKeeper 服务器列表,由英文逗号间隔的host:port字符串组成,每一个都代表一台 ZooKeeper 机器,例如:192.168.1.1:2181,192.168.1.2:2181,192.168.1.3:2181,这样就为客户端指定了三台服务器地址。
       另外,也可以在 connectString 中设置客户端连接上 ZooKeeper 后的根目录,方法是在host:port字符串之后添加上这个根目录,例如:192.168.1.1:2181,192.168.1.2:2181,192.168.1.3:2181/zk-book,这样就指定了该客户端连接上 ZooKeeper 服务器之后,所有对 ZooKeeper 的操作,都会基于这个根目录。例如,客户端对/foo/bar的操作,都会指向节点/zk-book/foo/bar——这个目录也叫Chroot,即客户端隔离命名空间,关于ZooKeeper中Chrooot的用法和示例,将在后面详细解释。
sessionTimeout        指定会话的超时时间,是一个以“毫秒”为单位的整型值。在 ZooKeeper 中有会话的概念,在一个会话周期内,ZooKeeper 客户端和服务端之间会通过心跳检测机制来维持会话的有效性,一旦在 sessionTimeout 时间内没有进行有效的心跳检测,会话就会失效。关于 ZooKeeper 的会话和心跳检测后面做详细解释。
watcher        ZooKeeper 允许客户端在构造方法中传入一个接口Watcher(org.apache.zookeeper.Watcher)的实现类对象来作为默认的 Watcher 事件通知处理器。当然,该参数可以设置为 null 以表明不需要设置默认的 Watcher 处理器。关于 ZooKeeper 的 Watcher 机制和实现原理后面会详细解释。
canBeReadOnly        这是一个 boolean 类型的参数,用于标识当前会话是否支持“read-only”模式。默认情况下,在 ZooKeeper 集群中,一个机器如果和集群中过半以上机器失去了网络连接,那么这个机器将不再处理客户端请求(包括读写请求)。但是在某些使用场景下,当 ZooKeeper 服务器发生此类故障的时候,我们还是希望 ZooKeeper 服务器能够提供读服务(当然写服务肯定无法提供)——这就是 ZooKeeper 的“read-only”模式。
sessionId和sessionPasswd        分别代表会话ID会话秘钥。这两个参数能够唯一确定一个会话,同时客户端使用这两个参数实现客户端会话复用,从而达到恢复会话的效果,具体使用方法是,第一次连接上 ZooKeeper 服务器时,通过调用 ZooKeeper 对象实现的以下两个接口,即可获得当前会话的ID秘钥long getSessionId();byte[] getSessionPasswd();获取到这两个参数值后,就可以在下次创建 ZooKeeper 对象实例的时候传入构造方法了。

注意,ZooKeeper 客户端和服务端会话的建立是一个异步的过程,也就是说在程序中,构造方法会在处理客户端初始化工作后立即返回,在大多说情况下,此时并没有真正建立好一个可用的会话,在会话的生命周期中处于“CONNECTING”的状态。

当该会话真正创建完毕后,ZooKeeper 服务端会向会话对应客户端发送一个事件通知,以告知客户端,客户端只有在获取这个通知之后,才算真正建立了会话。

该构造方法内部实现了与 ZooKeeper 服务器之间的TCP连接的创建,负责维护客户端会话的生命周期,现在暂不对这些细节做更多详解,关于 ZooKeeper 客户端与服务端之间的连接创建过程及其内部原理,将在后面详细介绍。

创建一个最基本的 ZooKeeper 会话实例

package com.lpf.zookeeper.ZooKeeper;

import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooKeeper;

import java.util.concurrent.CountDownLatch;

// Java API->创建连接->创建一个最基本的ZooKeeper会话实例
public class ZooKeeper_Constructor_Usage_Simple implements Watcher {
    private static CountDownLatch connectedSemaphore = new CountDownLatch(1);

    public static void main(String[] args) throws Exception {
        ZooKeeper zookeeper = new ZooKeeper("localhost:2181", 5000, new ZooKeeper_Constructor_Usage_Simple());
        System.out.println(zookeeper.getState());
        try {
            connectedSemaphore.await();
        } catch (InterruptedException e) {
        }
        System.out.println("ZooKeeper session established.");
    }

    public void process(WatchedEvent event) {
        System.out.println("Receive watched event:" + event);
        if (KeeperState.SyncConnected == event.getState()) {
            connectedSemaphore.countDown();
        }
    }
}

运行程序,输出结果如下:

CONNECTING
Receive watched event:WatchedEvent state:SyncConnected type:None path:null
ZooKeeper session established.

在上面这个程序片段中,我们使用第一种构造方法(ZooKeeper(String connectString, int sessionTimeout, Watcher watcher);)来实例化了一个 ZooKeeper 对象,从而建立了会话。

另外,ZooKeeper_Constructor_Usage 类实现了 Watcher 接口,重写了 process 方法,该方法负责处理来自 ZooKeeper 服务端的 Watcher 通知,在收到服务端发来的 SyncConnected 事件后,解除主程序在 CountDownLatch 上的等待阻塞。至此,客户端会话创建完毕。

创建一个复用 sessionId 和 sessionPasswd 的 ZooKeeper 对象实例

扫描二维码关注公众号,回复: 2903881 查看本文章

在上面列出的 ZooKeeper 客户端构造方法中,我们看到 ZooKeeper 构造方法允许传入 sessionId 和 sessionPasswd ——客户端传入 sessionId 和 sessionPasswd 的目的是为了复用会话,以维持之前会话的有效性。下面代码是一个复用 sessionId 和 sessionPasswd 来创建 ZooKeeper 对象实例的示例。

package com.lpf.zookeeper.ZooKeeper;

import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooKeeper;

import java.util.concurrent.CountDownLatch;

// 创建一个最基本的ZooKeeper对象实例,复用sessionId和sessionPasswd
public class ZooKeeper_Constructor_Usage_With_SID_PASSWD implements Watcher {
    private static CountDownLatch connectedSemaphore = new CountDownLatch(1);

    public static void main(String[] args) {
        try {
            ZooKeeper zookeeper = new ZooKeeper("localhost:2181", 5000,//
                    new ZooKeeper_Constructor_Usage_With_SID_PASSWD());
            connectedSemaphore.await();
            long sessionId = zookeeper.getSessionId();
            byte[] passwd = zookeeper.getSessionPasswd();

            //Use illegal sessionId and sessionPassWd
            zookeeper = new ZooKeeper("localhost:2181", 5000,//
                    new ZooKeeper_Constructor_Usage_With_SID_PASSWD(),//
                    1l,//
                    "test".getBytes());
            //Use correct sessionId and sessionPassWd
            zookeeper = new ZooKeeper("localhost:2181", 5000,//
                    new ZooKeeper_Constructor_Usage_With_SID_PASSWD(),//
                    sessionId,//
                    passwd);

            Thread.sleep(Integer.MAX_VALUE);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void process(WatchedEvent event) {
        System.out.println("Receive watched event:" + event);
        if (KeeperState.SyncConnected == event.getState()) {
            connectedSemaphore.countDown();
        }
    }
}

运行程序,输出结果如下:

Receive watched event:WatchedEvent state:SyncConnected type:None path:null
Receive watched event:WatchedEvent state:Expired type:None path:null
Receive watched event:WatchedEvent state:SyncConnected type:None path:null

从上面这个示例程序和结果输出中,我们可以看出,第一次使用了错误的 sessionId 和 sessionPasswd 来创建 ZooKeeper 客户端的实例,结果客户端接收到了服务端的 Expired 事件通知;而第二次则使用正确的 sessionId 和 sessionPasswd 来创建客户端的实例,结果连接成功。

猜你喜欢

转载自blog.csdn.net/liupeifeng3514/article/details/82082683