ZooKeeper是一个分布式协调服务,客户端可以通过集群里的任何一个ZkServer来访问ZooKeeper的服务,无论该ZkServer是leader还是follower。任何客户端在初次和ZkServer建立连接时,都是通过CreateSession这个操作来完成的。CreateSession和setData、delete等操作一样,都是事务型的,所以需要由leader ZkServer来完成。CreateSession成功后,leader节点上维护着所有客户端的session信息,并且周期性地检查这些客户端的session信息,一旦客户端与ZooKeeper服务端失去连接,并且时间达到session timeout(客户端在CreateSession时设定的),那么leader ZkServer就会把超时的客户端关闭掉,并且把该客户端所创建的所有临时znode也都删除掉。
以上的内容,在大部分ZooKeeper的资料中都会提到。但是有一个问题,那就是我上面说到,客户端可以通过任何一个ZkServer来访问ZooKeeper服务,不妨假设是一个follower ZkServer,这个客户端的session信息,是由leader ZkServer来维护的,那么leader怎么知道这个客户端和follower ZkServer的连接是不是正常呢?
带着这个问题,我翻了翻源代码。ZooKeeper源代码写得还是挺好的,抽象程度挺高的,看得我有点绕,不过还是找到了一些蛛丝马迹。简单点地说,就是以下几点:
- 客户端会不时地向所连接的ZkServer发送ping消息,ZkServer接收到ping消息,或者任何其它消息的时候,都会将客户端的session_id,session_timeout记录在一个map中。假设客户端连接的是一个follower ZkServer,那么每次客户端访问这个follower ZkServer的时候,map中都会记一条session的记录(同一个session_id最多只有一条)。
- Leader ZkServer会周期性(每半个ticktime)地向所有的follower ZkServer发送心跳消息(ping),follower接收到ping消息后,会将记录session信息的map作为返回消息,返回给leader ZkServer,同时清空follower本地的map. Leader ZkServer使用这些信息,刷新leader上维护的Session,也就是重新计算客户端的超时时间。
- 一旦在session timoue的时间内,leader即没有从其它follower上收集到客户端的session信息,也没有直接接收到该客户端的任何请求,那么该客户端的session就会被关闭。
通过上面的流程,Leader就可以掌握当前ZooKeeper集群的所有客户端的session信息。