Zookeeper-Session控制原理与错误详解
Zookeeper-Session控制原理与异常详解F1当Client与Server建立连接后,Server会根据client传递的sessionTime
Zookeeper-Session控制原理与异常详解
F1
当Client与Server建立连接后,Server会根据client传递的sessionTimeout时间做一次计算,比如它不能超过server配置的最大/最小过期时间等.并发回给client一个合理的值.对于重连接操作,client会交付给server现有的sessionId,如果此session已经过期,则返回一个负值.client可以根据此值判断出Session是否已经Expired...readOnly参数有客户端指定, 即canReadOnly参数,如果为true则表示当前Client允许和readOnly服务器建立连接,当server处于选举过程中或者"危险期"("少数派")是,server处于readOnly状态;server会把自己的状态在建立连接之后的首个响应包中返回给client;如果此参数无false,则表示client不允许与readOnly服务器建立连接,如果不幸与readOnly服务器建立了连接,则直接导致连接被关闭,client需要重新选择服务器.如果连接了ReadOnly服务器,此时client的"连接"状态为CONNECTEDREADONLY,否则为CONNECTED;此后可以通过client进行正常的读写操作;如果在readOnly模式下,发送write操作(比如create,setData)等,那么server将会校验请求类型,极有可能在响应结果中告知一个error,此时客户端接收到error后会抛出异常,对于API调用者,则需要捕获并处理.如果Client连接了一个readOnly服务器,那么在SendThread中会开启一个处理分支,并周期性的检测服务器列表,依次建立连接并查找出RWServer,一旦查到,将会以异常的方式close当前连接,并和RWServer重连.对于Zookeeper客户端实例,所有的请求都将队列化,首先将请求加入队列,并阻塞当前正在处理的packet,packet为客户端请求的封装对象,阻塞的方式为packet.wait..当server端返回了响应结果,那么导致packet.notifyAll();一个奇怪的问题就是,在client重连操作或者关闭连接时,都将导致请求队列被clean,那么对于API 调用者,则会收到异常,那么调用者需要重新尝试操作.sessionTimeout的值有Server最终决定,Client通过此值用来判断SessionTimeoutException触发的时机..在Client与server交互期间,可能因为IO的阻塞,导致client等待的时间超过限制,最终客户端触发SessionTimeoutException,此异常并非致命,但是client会"觉得"sever可能不可用,则尝试和其他server重新连接.(参考6)).Client为了让Server感知到Session的活性,则周期性的向Server发送ping消息,此周期时间比SessionTimeout值要小.如果Client重连接到Server之后,server校验发现此Session信息已经不存在(只针对重连),那么Server将会在响应包中告知此异常,此异常直接导致Client和Server的连接被关闭(SendThread状态被置为不可用);此后Client实例将不可用,除非新建Zookeeper实例.
?Client是否首次连接,主要基于sessionId的判断,对于首次连接(新会话),那么sessionId为0,对于重连接操作,sessionId基于现有的.createSession过程有Leader操作,Follower只需要把此信息转发给Leader即可.leader根据目前现有的最大SessionId + 1,作为新会话的sessionId,并将信息保存在sessionsWithTimeout,sessionsById,sessionSets这三个数据结构中(参见上述);其中sessionsWithTimeout是ZKDatabase的一部分,如果createSession提议被集群确认,那么session信息将会被持久存在所有server的ZKDatabase中.createSession创建成功后,Follower即可以想Client反馈结果,并交付sessionId,同时表示和Client之间的连接即可以处理正常的业务.对于reopenSession稍微复杂,多了一步session的过期校验,校验的手段非常简单,就是从当前的session列表中查找,如果sessio还存在,则表示未过期..不过此过程仍然有Leader控制.LeaderZookeeper类使用了SessionTracker来跟踪session,此tracker是一个线程,周期性的检测session过期情况.对于createSession或者reopenSession会导致sessionsWithTimeout,sessionsById,sessionSets三个数据结构中session信息的添加,其中sessionSets是个Map(参见上述),key为tickTime,这个值为session下一次过期的时间戳(System.currentTimeMillis() + timeout,并对"expirationInterval"取整).其主要目的就是把所有的session按照即将过期的时间梯度分类,并递增的逐次去检测过期.Follower/Observer也持有了一个LearnerSessionTracker,这个tracker和Leader持有的SessionTracker有却别,它不是一个线程,它不周期性的检测session过期.它只负责当client请求时,更新session的过期时间.并且在Follower/Observer与Leader的ping消息中,将在自己server上活跃(与当前server建立连接的Session)的session列表发送给Leader;Leader被动的根据此session列表来延迟Session过期操作;说白了,session的活跃性与否是Follower知道,但是Follower需要告诉Leader哪些是活跃的,最终有Leader来检测过期与否.对于Leader接收到Follower/Observer的活跃session列表之后,将会操作SessionTracker中的sessionSets,并将活跃的session从此当前过期梯度的sessionSets中移除,因此在SessionTracker的下一次过期检测时就不会得到它们..(如果session活跃,那么tracker将会把此session放在当前过期梯度的下一个梯度中,每个梯度的时间差为一个"expirationInterval").对于Leader : SessionTrackerImpl + LeaderZookeeperServer;对于Follower: LearnerSessionTracker + LearnerZookeeperServer
?关于ZK Session机制中还有很多疑点,路很长,我只能帮到这儿了..