天天看點

ZooKeeper學習之關于Servers和Sessions

Session是Zookeeper的一個重要的抽象。有序的保證,ephemeral znode,watch都與session緊緊關聯。

session的跟蹤機制也是很重要的一塊。

ZooKeeper server的一個重要任務就是跟蹤并維護這些session。運作于standalone模式下的單獨的server會維護所有的session,而在quorum模式下由leader來維護。leader和standalone模式的server實際上跑着相同的session tracker(可以參考SessionTracker類和SessionTrackerImpl類)。follower僅僅是簡單的把client送出的session資訊轉發到leader(參考LearnerSessionTracker類)。

為了保活(keep alive)session,server需要接收到session的心跳。心跳的形式可以是一個新的請求或者顯式的ping消息(參考LearnerHandler.run())。兩種情況下,server通過更新session的逾時時間來touch session(參考SessionTrackerImpl.touchSession())。在quorum模式下,leader發送一個ping消息給它的learner,learner傳回自從last PING之後的一個session清單。leader每隔半個tick就會發送一個ping給learner。是以,如果一個tick被設定成2秒,那麼leader每隔一秒就會發送一個ping。

對于session的過期有2個重要的要點。一個稱為expiry queue的資料結構(參考ExpiryQueue類)用來維護session的過期。這個資料結構使用bucket來維護session,每一個bucket對應一個時間範圍,這個範圍内的session會過期,leader每次會讓一個bucket的session過期。為了決定哪一個bucket的session過期,如果有的話。當下一個deadline到來時,一個線程會檢查這個expiry queue來找出要過期的bucket。這個線程在deadline到來之前處于sleep狀态,當它被喚醒時,它會取出expiry queue的一批session,讓它們過期。當然取出的這批資料可能是空的。

為了維護這些bucket,leader把時間分成一些片段,以expirationInterval為機關進行分割,并把每個session配置設定到它的過期時間對應的bucket裡。更具體的說,是對下面的表達式進行計算,當session的過期時間更新時,根據結果來決定它屬于哪一個bucket。

(expirationTime / expirationInterval + 1) * expirationInterval

舉個例子來說明,比如expirationInterval為2,session的逾時時間為10。那麼這個session配置設定到bucket 12中((10/2+1)*2)。注意當我們touch這個session時這個逾時時間會增加,是以我們要把這個session移動到其他的bucket中來推遲過期。

使用bucket的模式來管理的一個主要原因是為了減少讓session過期這項工作的系統開銷。一個生産環境中的ZooKeeper機器可能會有數千個client,對應着數千個session。在這種場景下要細粒度的檢查session過期是不合适的。如果expirationInterval短的話,那麼檢查session過期的粒度會不錯。目前是一個tick,相當于1秒鐘。