1)几个重要概念
-
ZooKeeper:客户端入口
-
Watcher:客户端注册的callback
-
ZooKeeper.SendThread: IO线程
-
ZooKeeper.EventThread: 事件处理线程,处理各类消息callback
-
ClientCnxnSocketNIO:继承自ClientCnxnSocket,专门处理IO
2)zookeeper初始化
-
应用提供watch实例
-
实例化zookeeper
-
实例化SendThread
-
实例化EventThread
-
启动zookeeper
3)以一个请求为例以 zk.exists("/root", false)为例
4)小结
4.1)
SendThread也并非完全对应与请求/响应模式,SendThread也会接受到节点变化的通知,此时客户端变成了服务端
4.2)时间和超时的控制
ClientCnxnSocket作为ClientCnxnSocketNIO的父类,
有3个关键的时间字段
-
now :每次轮询select之前更新,或者发生错误是在catch段中更新为当前时间
-
lastHeard:在读取了响应,包括上面提到的connect型请求和常规命令型请求的响应以及完成网络连接时更新为当前时间
-
lastSend:每次发送完ping 命令和请求以及完成网络连接时更新为当前时间
有下面几个超时设置
-
sessionTimeout:zookeeper初始化时设置的
-
readTimeout:sessionTimeout * 2 / 3
-
connectTimeout:sessionTimeout / hostProvider.size(); //hostProvider.size()为zookeeper服务器个数
-
getIdleRecv():now - lastHeard
-
getIdleSend():now - lastSend
-
SessionTimeout的计算
-
如果没有完成连接to=connectTimeout - getIdleRecv()
-
如果完成连接to=readTimeout - getIdleRecv()
-
如果to<=0 就会抛出SessionTimeoutException
4.3)什么时候ping
计算timeToNextPing = readTimeout / 2-getIdleSend()
如果timeToNextPing <= 0,发送ping请求(只是将ping请求放入outgoingQueue,并不发生IO)
4.4)select阻塞多久
如果上述的0<timeToNextPing<to,那么阻塞时长为timeToNextPing,否则为to
如果有写请求,select会被唤醒
4.5)sendThread的工作原理
该线程作为zookeeper客户端的核心部分专门负责IO处理
-
计算select timeout(上面提到的to)
-
检查空闲时间,有可能抛出SessionTimeoutException或者发送ping
-
使用select轮询,获取网络事件(连接、读、写)也就是这3类
4.6)请求中的Watcher和StatCallback的差别
两个都是callback,两者都由EventThread,但后者控制调用线程是否会阻塞等待响应
4.7)IO模型
如图