Apache Curator 2.x 會話超時事件丟失

    在使用Apache Curator2.11操做Zookeeper時,發現這麼一個場景:服務器

    建立CuratorFramework時,指定的失敗重試策略嘗試的總時間tryTime超過了會話超時和鏈接超時中最大值maxTimeout時,若是發生網絡中斷,且網絡恢復時發生在大於會話超時和鏈接超時中最大值maxTimeout,小於重試策略嘗試的總時間tryTime時,Curator中的ConnectionStateListner監聽器將接收不到ConnectionState.LOST事件,即便使用Watcher也獲取不到Expired事件。場景說明以下圖:網絡

在最新Apache Curator官方文檔中有關於ConnectionState.LOST的描述,內容以下:框架

    注意最後一句話,大概意思是說:3.x之前版本中ConnectionState.LOST僅表示重試策略失敗,不表明會話超時。異步

    查看curator源碼發現,觸發ConnectionState.LOST事件時有兩種狀況:線程

    1.重試策略失敗時,代碼以下:
    對象

    2.客戶端接收到會話超時事件時:
    事件

    那在curator2.11中會話超時事件丟失的緣由是什麼呢,通過跟蹤代碼發現,在CuratorFrameworkImpl客戶端start()時,內部開啓了一個線程不斷的循環用於處理異步提交的操做:文檔

在處理異步請求的邏輯中,每次都會從client中獲取Zookeeper對象,並在獲取Zookeeper時,判斷若是當前處於未鏈接成功狀態時,則重試嘗試鏈接,並檢查當前等待恢復鏈接的時間是否超過會話超時和鏈接超時之間的最大值,若是未超過,則拋出CuratorConnectionLossException,若是超出會話超時和鏈接超時之間的最大值,則客戶端自動重置Zookeeper對象,關閉並釋放原來的Zookeeper,並嘗試從新建立一個新的Zookeeper對象,代碼以下:源碼

當客戶端reset了Zookeeper後,客戶端放棄了原來的會話,而嘗試與服務器創建一個新的會話。此時,已經超過了會話超時時間,服務器端已經把原來的會話從會話桶中移走,並把該會話建立的臨時節點等丟失掉。這時,若是網絡恢復了,客戶端就會按新的會話請求與服務器創建鏈接,服務器正常接收這個請求,建立會話,返回給客戶端新的會話的信息。至此,原來的會話的過時事件已經丟失。io

    綜合來看,在重試策略有效期內,Curator客戶端對當前會話的有效性進行檢查,當超過會話超時與鏈接超時最大值仍未恢復鏈接時,Curator的重連機制處理對原來的會話進行關閉,釋放並嘗試建立一個新的會話,網絡恢復後,客戶端與服務器創建新的會話成功,以前的會話超時事件就丟失了,這樣沒法獲取ConnectionState.LOST狀態了。

    因此若是在ConnectionStateListner中監聽ConnectionState.LOST狀態,並在該狀態下去恢復臨時節點時,就會出現沒法成功恢復臨時節點的狀況。

    該怎麼解決呢?丟失的緣由主要是由於,客戶端在會話超時時reset了Zookeeper對象。因此咱們只要保證重試策略的總時間設置的比會話超時和鏈接超時最大值小便可,這樣,Curator會在重置Zookeeper對象以前重試策略失敗,這樣就會變爲ConnectionState.LOST狀態,這時咱們能夠恢復臨時節點,但若是在重試策略失敗後會話超時前恢復網絡,就有可能會重複建立臨時節點。因此在使用時須要謹慎,咱們能夠建立CreateMode.EPHEMERAL類型而非CreateMode.EPHEMERAL_SEQUENTIAL類的臨時節點,或恢復節點前判斷節點是否存在,不存在時再建立該節點,這樣不會建立第二個臨時節點而形成問題。

    固然咱們在使用Curator框架時,想使用它的重試策略,不能爲了這個會話超時丟失的問題而不使用它的會話超時自動恢復會話功能。可咱們又想得到會話超時事件,想在ConnectionState.LOST狀態時作一些事情。咱們可使用兩種重試策略的客戶端,一個客戶端用於感知會話超時事件,保證它的重試策略的總時間設置的比會話超時和鏈接超時最大值小;另外一個客戶端用於咱們業務上的其餘操做,它的重試策略能夠根據咱們的實際狀況來設置便可。

相關文章
相關標籤/搜索