ZooKeeper中“对话”的那些事儿
一、基本概念
ZooKeeper Client欲请求ZooKeeper Server的服务,首先必须与ZooKeeper Server进行连接,建立“会话”(Session)。
二、行为
2.1、结束“会话”
2.1.1、由“会话”的Client端显式结束“会话”
举例说明,假如现在有如下代码:
package com.dslztx.zookeeper;
import org.apache.zookeeper.*;
import java.io.IOException;
import java.util.Date;
public class Master {
String hostPort;
Integer sessionTimeout;
Watcher watcher;
ZooKeeper zk = null;
public Master(String hostPort, Integer sessionTimeout, Watcher watcher) {
this.hostPort = hostPort;
this.sessionTimeout = sessionTimeout;
this.watcher = watcher;
}
void startZK() throws IOException {
zk = new ZooKeeper(hostPort, sessionTimeout, watcher);
}
void stopZK() throws InterruptedException {
if (zk != null) {
zk.close();
}
}
public static void main(String[] args) throws IOException, InterruptedException {
String hostPort = "127.0.0.1:2181";
Integer sessionTimeout = 600000;
Watcher watcher = new SessionWatcher();
Master m = new Master(hostPort, sessionTimeout, watcher);
m.startZK();
System.out.println("start to create session,now time:" + new Date());
// 等待两分钟让session能够完成初始化
Thread.sleep(60000 * 2);
// 显式关闭session
System.out.println("close the session,now time:" + new Date());
m.stopZK();
// 杀死进程
System.out.println("kill process,now time:" + new Date());
System.exit(0);
}
}
class SessionWatcher implements Watcher {
public void process(WatchedEvent watchedEvent) {
System.out.println(watchedEvent);
}
}
运行后结果如图1所示。
图1
由图1可知,此时建立的“会话”的ID为“0x1540339295d0004”。在该程序运行过程中和运行后,可以执行ZooKeeper Server的dump
命令,从而可以查看该“会话”的信息。查看结果分别如图2和3所示。
图2
图3
由图2,图3可知,一旦在“会话”的Client端发出结束“会话”的指令,那么“会话”会立即被结束。
2.1.2、由“会话”的Server端基于过期认定,将“会话”结束
package com.dslztx.zookeeper;
import org.apache.zookeeper.*;
import java.io.IOException;
import java.util.Date;
public class Master {
String hostPort;
Integer sessionTimeout;
Watcher watcher;
ZooKeeper zk = null;
public Master(String hostPort, Integer sessionTimeout, Watcher watcher) {
this.hostPort = hostPort;
this.sessionTimeout = sessionTimeout;
this.watcher = watcher;
}
void startZK() throws IOException {
zk = new ZooKeeper(hostPort, sessionTimeout, watcher);
}
void stopZK() throws InterruptedException {
if (zk != null) {
zk.close();
}
}
public static void main(String[] args) throws IOException, InterruptedException {
String hostPort = "127.0.0.1:2181";
Integer sessionTimeout = 600000;
Watcher watcher = new SessionWatcher();
Master m = new Master(hostPort, sessionTimeout, watcher);
m.startZK();
System.out.println("start to create session,now time:" + new Date());
// 等待两分钟让session能够完成初始化
Thread.sleep(60000 * 2);
// 杀死进程
System.out.println("kill process,now time:" + new Date());
System.exit(0);
}
}
class SessionWatcher implements Watcher {
public void process(WatchedEvent watchedEvent) {
System.out.println(watchedEvent);
}
}
运行后结果如图4所示。
图4
由图4可知,此时建立的“会话”的ID为“0x1540339295d0003”。在该程序运行过程中和运行后,可以执行ZooKeeper Server的dump
命令,从而可以查看该“会话”的信息。查看结果分别如图5,6,7,8和9所示。
图5
图6
图7
图8
图9
由图5,图6,图7,图8和图9可知,对于“会话”的Server端来说,只有该“会话”的Client端在“timeout”(这个“timeout”的值在这里被取为“600000”,即10分钟)时间内没有发送任何数据,该“会话”才会被判定为“过期”,该“会话”才会被结束。
2.2、重连另外一台ZooKeeper Server,原“会话”不变
某个ZooKeeper Client与某个ZooKeeper Server进行连接,建立了“会话”,当该ZooKeeper Client与该ZooKeeper Server之间的连接断开,该ZooKeeper Client会选中ZooKeeper Server集群中某台ZooKeeper Server(有可能是原来的ZooKeeper Server)进行重连,得到的“会话”是原来的“会话”,而不是新建了一个“会话”,最明显的证据是“会话”ID没有发生变化。
三、其他
“会话”的Client端会不断向它的Server端发送心跳请求,以保持“会话”的活跃,避免该“会话”的Server端在“timeout”时间内收不到任何来自Client端的数据,从而将该“会话”判定为“过期”,并将其结束。
备注:
本文是对《ZooKeeper》 Chapter 2 Getting to Grips with ZooKeeper中的“4.2、使用ZooKeeper实现一个分布式应用程序之‘会话’”所描述内容的验证和扩展。