zookeeper会话及超时处理

zookeeper session也就是会话,用于维持客户端与服务器之间的连接状态。

Session什么时候创建

在ZooKeeper中,客户端和服务端建立连接后会创建一个session(会话),每一个session对应一个全局唯一的会话ID(Session ID)。就像浏览器和Web服务器一样,首次连接Web服务器的时候为了跟踪客户端,Web服务器会创建一个Session。

Session超时

zookeeper服务器和客户端之间维持的是一个长连接,客户端会定时向服务器发送心跳来维持Session的有效性(每次发送心跳就会刷新session超时时间)。正常情况下Session一直有效,并且ZK集群所有机器上都保存这个Session信息。当出现网络中断或zookeeper服务挂掉时,客户端会主动在地址列表(实例化ZK对象的时候传入构造方法的那个参数connectString)中选择新的地址进行连接(如果没有备选地址,会不断重试之前的那个地址),如果有新的地址可以连接,在中断时长小于sessionTimeout值时,zookeeper客户端自动重连。如果中断时长大于sessionTimeout值时,将出现session expired的异常,这个时候就需要开发者手动做一些处理,比如使用zookeeper的create重建连接。

如何监听Session超时事件

在创建zookeeper对象时,指定的Watcher是zookeeper客户端默认的Watcher,可以在它的process方法中监听到Session超时事件,具体做法:

/**
     * 当type=None(-1)时,有四种情况:
     *  1. zookeeper已连接
     *  2. 会话超时!
     *  3. zookeeper连接已关闭
     *  4. zookeeper认证失败
     * @param watchedEvent zookeeper event
     */
    @Override
    public void process(WatchedEvent watchedEvent) {
        Event.EventType type = watchedEvent.getType();
        Event.KeeperState state = watchedEvent.getState();
        int stateValue = state.getIntValue();
        logger.info("监听到变化,type=" + type.getIntValue() + ",name=" + type.name());
        logger.info("state=" + state.getIntValue() + ",name=" + state.name());
        if (type.getIntValue() == Event.EventType.None.getIntValue()) {
            if (stateValue == Event.KeeperState.SyncConnected.getIntValue()) {
                logger.info("zookeeper已连接!");
                countDownLatch.countDown();
            }else if (stateValue == Watcher.Event.KeeperState.Expired.getIntValue()) {
                logger.info("zookeeper会话超时!");
                //zookeeper连接是异步的,所以用CountDownLatch保证zookeeper连接成功后再通知Listeners
                countDownLatch = new CountDownLatch(1);
                ZooKeeper zooKeeper = createNewZookeeper();
                try {
                    countDownLatch.await();
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
                noticeListener(zooKeeper);
            }else if (stateValue == Watcher.Event.KeeperState.Closed.getIntValue()) {
                logger.info("zookeeper连接已关闭!");
            }else if (stateValue == Watcher.Event.KeeperState.AuthFailed.getIntValue()) {
                logger.info("zookeeper认证失败!");
            }
        }

Seession超时后如何重建连接,需要注意什么

重新new 一个zookeeper即可,使用zookeeper提供的API,如下:

public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher) throws IOException{
        this(connectString, sessionTimeout, watcher, false);
}

但是需要注意session超时之后,之前使用Java API注册的Watcher将丢失,比如:

public void addWatch(String basePath, AddWatchMode mode)
            throws KeeperException, InterruptedException {
        addWatch(basePath, watchManager.defaultWatcher, mode);
}

所以在重建连接之后,你需要重新添加监听。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容