【ZooKeeper Notes 12】ZooKeeper 会话超时

转载请注明:@ni掌柜 nileader@gmail.comjava

一、会话概述apache

在ZooKeeper中,客户端和服务端创建链接后,会话随之创建,生成一个全局惟一的会话ID(Session ID)。服务器和客户端之间维持的是一个长链接,在SESSION_TIMEOUT时间内,服务器会肯定客户端是否正常链接(客户端会定时向服务器发送heart_beat,服务器重置下次SESSION_TIMEOUT时间)。所以,在正常状况下,Session一直有效,而且ZK集群全部机器上都保存这个Session信息。在出现网络或其它问题状况下(例如客户端所链接的那台ZK机器挂了,或是其它缘由的网络闪断),客户端与当前链接的那台服务器之间链接断了,这个时候客户端会主动在地址列表(实例化ZK对象的时候传入构造方法的那个参数connectString)中选择新的地址进行链接。服务器

二、链接断开网络

好了,上面基本就是服务器与客户端之间维持会话的过程了。在这个过程当中,用户可能会看到两类异常CONNECTIONLOSS(链接断开)和SESSIONEXPIRED(Session过时)。链接断开(CONNECTIONLOSS)通常发生在网络的闪断或是客户端所链接的服务器挂机的时候,这种状况下,ZooKeeper客户端本身会首先感知到这个异常,具体逻辑是在以下方法中触发的:session

  
  
           
  
  
  1. void org.apache.zookeeper.ClientCnxn.SendThread.run(){ 
  2. …… 
  3. …… 
  4.     } catch (Throwable e) { 
  5.         if (closing) { 
  6.             if (LOG.isDebugEnabled()) { 
  7.                 // closing so this is expected 
  8.                 LOG.debug("An exception was thrown while closing send thread for session 0x" 
  9.                         + Long.toHexString(getSessionId()) 
  10.                         + " : " + e.getMessage()); 
  11.             } 
  12.             break
  13.         } else { 
  14.             // this is ugly, you have a better way speak up 
  15.             if (e instanceof SessionExpiredException) { 
  16.                 LOG.info(e.getMessage() + ", closing socket connection"); 
  17.             } else if (e instanceof SessionTimeoutException) { 
  18.                 LOG.info(e.getMessage() + RETRY_CONN_MSG); 
  19.             } else if (e instanceof EndOfStreamException) { 
  20.                 LOG.info(e.getMessage() + RETRY_CONN_MSG); 
  21.             } else if (e instanceof RWServerFoundException) { 
  22.                 LOG.info(e.getMessage()); 
  23.             } else { 
  24.     ……                 
  25.     ……                     

一种场景是Server服务器挂了,这个时候,ZK客户端首选会捕获异常,以下:socket

捕获异常后,ZK客户端会打印相似于以下日志:ide

  
  
           
  
  
  1. EndOfStreamException: Unable to read additional data from server sessionid 0x13ab17ad9ec000b, likely server has closed socket 

而后作一些socket链接的善后工做。接下去是客户端从新选择一个Server Ip尝试链接,逻辑如代码C2-1所示,这里主要就是从地址列表中获取一个新的Server地址进行链接,关于这个地址如何获取,请查看这个文章:《ZooKeeper客户端地址列表的随机原理》。this

  
  
           
  
  
  1. [C2-1
  2. private void startConnect() throws IOException { 
  3.     state = States.CONNECTING; 
  4.  
  5.     InetSocketAddress addr; 
  6.     if (rwServerAddress != null) { 
  7.         addr = rwServerAddress; 
  8.         rwServerAddress = null
  9.     } else { 
  10.         addr = hostProvider.next(1000); 
  11.     } 
  12.  
  13.     LOG.info("Opening socket connection to server " + addr); 
  14.  
  15.     setName(getName().replaceAll("\\(.*\\)"
  16.             "(" + addr.getHostName() + ":" + addr.getPort() + ")")); 
  17.     try { 
  18.         zooKeeperSaslClient = new ZooKeeperSaslClient("zookeeper/"+addr.getHostName()); 
  19.     } catch (LoginException e) { 
  20.         LOG.warn("SASL authentication failed: " + e + " Will continue connection to Zookeeper server without " 
  21.                 + "SASL authentication, if Zookeeper server allows it."); 
  22.         eventThread.queueEvent(new WatchedEvent( 
  23.                 Watcher.Event.EventType.None, 
  24.                 Watcher.Event.KeeperState.AuthFailed, null)); 
  25.     } 
  26.     clientCnxnSocket.connect(addr); 

 程序运行过程当中,整个过程日志打印大体以下:编码

  
  
           
  
  
  1. 2012-10-31 09:09:57,379 - INFO  [main-SendThread(test.zookeeper.connection_string2:2181):zookeeper.ClientCnxn$SendThread@1053] - Unable to read additional data from server sessionid 0x23ab45c87df0000, likely server has closed socket, closing socket connection and attempting reconnect 
  2.  
  3. 收到事件通知:Disconnected 
  4.  
  5. 获取数据成功,path:/nileader 
  6. 2012-10-31 09:09:58,293 - INFO  [main-SendThread-zookeeper.ClientCnxn$SendThread@933] - Opening socket connection to server /1.2.1.1:2181 
  7.  
  8. 2012-10-31 09:09:58,294 - WARN  [main-SendThread-client.ZooKeeperSaslClient@123] - SecurityException: java.lang.SecurityException: Unable to locate a login configuration occurred when trying to find JAAS configuration. 
  9.  
  10. 2012-10-31 09:09:58,295 - INFO  [main-SendThread-client.ZooKeeperSaslClient@125] - Client will not SASL-authenticate because the default JAAS configuration section 'Client' could not be found. If you are not using SASL, you may ignore this. On the other hand, if you expected SASL to work, please fix your JAAS configuration. 
  11.  
  12. 2012-10-31 09:09:58,296 - INFO  [main-SendThread-zookeeper.ClientCnxn$SendThread@846] - Socket connection established to test.zookeeper.connection_string/1.2.1.1:2181, initiating session 
  13.  
  14. 2012-10-31 09:09:58,299 - INFO  [main-SendThread-zookeeper.ClientCnxn$SendThread@1175] - Session establishment complete on server test.zookeeper.connection_string/1.2.1.1:2181, sessionid = 0x23ab45c87df0000, negotiated timeout = 10000 
  15.  
  16. 收到事件通知:SyncConnected 

 因此,如今对于“链接断开”这个过程就一目了然了,核心流程以下:spa

ZK客户端捕获“链接断开”异常 ——> 获取一个新的ZK地址 ——> 尝试链接

在这个流程中,咱们能够发现,整个过程不须要开发者额外的程序介入,都是ZK客户端本身会进行的,而且,使用的会话ID都是同一个,因此结论就是:发生CONNECTIONLOSS的状况,应用不须要作什么事情,等待ZK客户端创建新的链接便可。

 三、会话超时
SESSIONEXPIRED发生在上面蓝色文字部分,这个一般是ZK客户端与服务器的链接断了,试图链接上新的ZK机器,可是这个过程若是耗时过长,超过了SESSION_TIMEOUT 后尚未成功链接上服务器,那么服务器认为这个Session已经结束了(服务器没法确认是由于其它异常缘由仍是客户端主动结束会话),因为在ZK中,不少数据和状态都是和会话绑定的,一旦会话失效,那么ZK就开始清除和这个会话有关的信息,包括这个会话建立的临时节点和注册的全部Watcher。在这以后,因为网络恢复后,客户端可能会从新链接上服务器,可是很不幸,服务器会告诉客户端一个异常:SESSIONEXPIRED(会话过时)。此时客户端的状态变成 CLOSED状态,应用要作的事情就是的看本身应用的复杂程序了,要从新实例zookeeper对象,而后从新操做全部临时数据(包括临时节点和注册Watcher),总之,会话超时在ZK使用过程当中是真实存在的。
 
因此这里也简单总结下,一旦发生会话超时,那么存储在ZK上的全部临时数据与注册的订阅者都会被移除,此时须要从新建立一个ZooKeeper客户端实例,须要本身编码作一些额外的处理。
 
四、会话时间(Session Time)
在《 ZooKeeper API 使用》一文中已经提到,在实例化一个ZK客户端的时候,须要设置一个会话的超时时间。这里须要注意的一点是,客户端并非能够随意设置这个会话超时时间,在ZK服务器端对会话超时时间是有限制的,主要是 minSessionTimeoutmaxSessionTimeout这两个参数设置的。(详细查看这个文章《 ZooKeeper管理员指南》)Session超时时间限制,若是客户端设置的超时时间不在这个范围,那么会被强制设置为最大或最小时间。 默认的Session超时时间是在2 * tickTime ~ 20 * tickTime。ZK实现以下,在这个方法中处理:
  
  
           
  
  
  1. ZooKeeperServer.processConnectRequest(ServerCnxn cnxn, ByteBuffer incomingBuffer) 

因此,若是应用对于这个会话超时时间有特殊的需求的话,必定要和ZK管理员沟通好,确认好服务端是否设置了对会话时间的限制。 

相关文章
相关标签/搜索