现在的位置: 首页 > 综合 > 正文

ZooKeeper的“会话终止”是这么出现的

2018年04月08日 ⁄ 综合 ⁄ 共 2541字 ⁄ 字号 评论关闭

转载请注明出处: jiq•钦's
technical Blog

经过我的测试,得出关于会话终止的下列结论:

客户端创建ZooKeeper实例连接到ZooKeeper服务端,设置会话超时时间为10s。

(1)若强制关闭ZooKeeper服务端(模拟其崩溃),客户端立马收到Disconnected连接断开事件,等待半个小时,再次启动ZooKeeper服务端,客户端收到SyncConnected连接建立事件,在这之前注册的watcher仍然有效,推测临时节点也一样有效。

(2)若断开客户端与服务端的网线(模拟网络断开),客户端立马收到Disconnected连接断开事件,等待11s再次插上网线,客户端收到Expired会话终止事件,之前注册的watcher不再有效,推测临时节点也会删除。


结论:

客户端连接到服务端的会话超时时间由服务端记录,客户端每隔一段时间(小于这个会话时间)向服务端发送心跳,服务端就不会将与这个客户端的会话设置为失效!!!

若服务端自己死掉了,将不给这个会话事件做倒计时,若是客户端关闭或者连接断开,就会进行会话终止倒计时,时间一到将会认定会话失效,认为客户端死掉。


还有一种情况可能出现会话终止:即客户端与服务端网络闪断,然后ZooKeeper客户端会自动从服务端地址列表中选择下一个ZooKeeper服务器进行重连,若这个重连时间超过设定的超时时间,比如10s,也会发送会话超时。

你可能会说重连怎么会超过10s呢?假如你在客户端再会话倒计时还剩7s的时候正要给服务端发送心跳,不幸网络刚好断开,然后选择一个重连,这个重连超过3s,那就超时了。


所以说,客户端开发人员进行ZooKeeper开发时,如果你注册到服务端的watcher以及创建的临时节点至关重要时,你可能不需要担心因为ZooKeeper服务器挂掉导致会话失效,但是一定要防备因为网络断开,然后经过会话超时时间之后又自动重新建立连接的情况,因为这个时候会话终止了!!!

如果网络经常闪断,但是断开时间不长,为求保险,可以讲会话超时时间设置长一点,一般30s。

是否可以设置为无限长,比如几天?

注意:实例化一个ZK客户端的时候,需要设置一个会话的超时时间。这里需要注意的一点是,客户端并不是可以随意设置这个会话超时时间,在ZK服务器端对会话超时时间是有限制的,主要是minSessionTimeout和maxSessionTimeout这两个参数设置的。如果客户端设置的超时时间不在这个范围,那么会被强制设置为最大或最小时间。 默认的Session超时时间是在2 * tickTime ~ 20 * tickTime。


下面附上我的测试程序:

注册了watcher的客户端:

public class ZooKeeperTest implements Watcher
{
	private CountDownLatch latch = new CountDownLatch(1);
	
	public ZooKeeper GetConnection() throws Exception
	{		
		ZooKeeper zk = new ZooKeeper("192.168.1.108:2181", 3000, this);
		latch.await();
		return zk;
	}
	
	@Override 
    public void process(WatchedEvent event ) { 
        System.out.println( "收到事件通知:" + event.getState() +"\n路径是:"+event.getPath()); 
        if (KeeperState.SyncConnected == event.getState() ) { 
            latch.countDown(); 
        } 
    } 
	
    public static void main(String[] args) throws Exception
    {
    	ZooKeeperTest obj = new ZooKeeperTest();
    	ZooKeeper zk = obj.GetConnection();
    	
    	System.in.read();
    	zk.close();
    } 
}

首先将ZooKeeper服务器强制关闭,过了很久很久在重新开启,输出如下:

收到事件通知:SyncConnected
路径是:null
收到事件通知:Disconnected
路径是:null
收到事件通知:SyncConnected
路径是:null


然后再跑一下我的修改ZooKeeper节点的程序:

public class NodeChangeTest implements Watcher
{
	private CountDownLatch latch = new CountDownLatch(1);
	
	public ZooKeeper GetConnection() throws Exception
	{		
		ZooKeeper zk = new ZooKeeper("192.168.1.108:2181", 3000, this);
		latch.await();
		return zk;
	}
	
	@Override 
    public void process(WatchedEvent event ) { 
        System.out.println( "收到事件通知:" + event.getState() +"\n"  ); 
        if (KeeperState.SyncConnected == event.getState() ) { 
            latch.countDown(); 
        } 
    } 
	public static void main(String[] args) throws Exception 
	{
		NodeChangeTest test = new NodeChangeTest();
		ZooKeeper zk = test.GetConnection();
		
		zk.setData("/test", "zNode2".getBytes(), -1);		
		zk.close();
	}
}


收到下面信息,表明watch时间触发:

收到事件通知:SyncConnected
路径是:/test

如果是将网线断开,过了5s又插上将会有如下输出:

收到事件通知:SyncConnected
路径是:null
收到事件通知:Disconnected
路径是:null
收到事件通知:Expired
路径是:null

修改ZooKeeper节点的程序也没有任何反应。

抱歉!评论已关闭.