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模型
如圖