「分佈式」 Lease機制

Lease機制

Lease 機制是最重要的分佈式協議,廣泛應用於各種實際的分佈式系統中。即使在某些系統中相似的設計不被稱為 lease,但我們可以分析發現其本質就是一種 lease 的實現。

本節從一個分佈式cache 系統出發介紹最初的 lease 機制,接著加以引申,探討 lease 機制的本質。最後介紹了 lease 機制最重要的應用:判定節點狀態。

1. 基於 lease 的分佈式 cache 系統

本節先通過討論一種分佈式 cache 系統的實例來介紹 lease 機制。Lease 機制最初也是被運用於這種系統。

基本的問題背景如下:在一個分佈式系統中,有一箇中心服務器節點,中心服務器存儲、維護著一些數據,這些數據是系統的元數據。系統中其他的節點通過訪問中心服務器節點讀取、修改其上的元數據。由於系統中各種操作都依賴於元數據,如果每次讀取元數據的操作都訪問中心服務器節點,那麼中心服務器節點的性能成為系統的瓶頸。為此,設計一種元數據 cache,在各個節點上cache 元數據信息,從而減少對中心服務器節點的訪問,提高性能。另一方面,系統的正確運行嚴格依賴於元數據的正確,這就要求各個節點上 cache 的數據始終與中心服務器上的數據一致,cache中的數據不能是舊的髒數據。最後,設計的 cache 系統要能最大可能的處理節點宕機、網絡中斷等異常,最大程度的提高系統的可用性。

為此,利用 lease 機制設計一套 cache 系統,其基本原理為如下。中心服務器在向各節點發送數據時同時向節點頒發一個 lease。每個 lease 具有一個有效期,和信用卡上的有效期類似,lease 上的有效期通常是一個明確的時間點,例如 12:00:10,一旦真實時間超過這個時間點,則 lease 過期失效。這樣 lease 的有效期與節點收到 lease 的時間無關,節點可能收到 lease 時該 lease 就已經過期失效。這裡首先假設中心服務器與各節點的時鐘是同步的,下節中討論時鐘不同步對 lease 的影響。中心服務器發出的 lease 的含義為:在 lease 的有效期內,中心服務器保證不會修改對應數據的值。因此,節點收到數據和 lease 後,將數據加入本地 Cache,一旦對應的 lease 超時,節點將對應的本地 cache數據刪除。中心服務器在修改數據時,首先阻塞所有新的讀請求,並等待之前為該數據發出的所有lease 超時過期,然後修改數據的值。

具體的服務器與客戶端節點一個基本流程如下:

流程 2.3.1:基於 lease 的 cache,客戶端節點讀取元數據:

1. 判斷元數據是否已經處於本地 cache 且 lease 處於有效期內

1.1 是:直接返回 cache 中的元數據

1.2 否:向中心服務器節點請求讀取元數據信息

1.2.1 服務器收到讀取請求後,返回元數據及一個對應的 lease

1.2.2 客戶端是否成功收到服務器返回的數據

1.2.2.1 失敗或超時:退出流程,讀取失敗,可重試

1.2.2.2 成功:將元數據與該元數據的 lease 記錄到內存中,返回元數據

流程 2.3.2:基於 lease 的 cache,客戶端節點修改元數據流程

1. 節點向服務器發起修改元數據請求。

2. 服務器收到修改請求後,阻塞所有新的讀數據請求,即接收讀請求,但不返回數據。

3. 服務器等待所有與該元數據相關的 lease 超時。

4. 服務器修改元數據並向客戶端節點返回修改成功

上述機制可以保證各個節點上的 cache 與中心服務器上的中心始終一致。這是因為中心服務器節點在發送數據的同時授予了節點對應的 lease,在 lease 有效期內,服務器不會修改數據,從而客戶端節點可以放心的在 lease 有效期內 cache 數據。

述基礎流程有一些性能和可用性上的問題,但可以很容易就優化改性。優化點一:服務器在修改元數據時首先要阻塞所有新的讀請求,造成沒有讀服務。進一步的優化是,當進入修改流程,服務器頒發的lease 有效期限選擇為已發出的 lease 的最大有效期限。實際使用中,第一層優化就足夠了。優化點二:服務器在修改元數據時需要等待所有的 lease 過期超時,從而造成修改元數據的操作時延大大增大。優化的方法是,在等待所有的 lease 過期的過程中,服務器主動通知各個持有lease的節點放棄lease並清除cache中的數據,如果服務器收到客戶端返回的確認放棄lease的消息,則服務器不需要在等待該 lease 超時。

2. lease 機制的分析

首先給出本文對 lease 的定義:Lease 是由頒發者授予的在某一有效期內的承諾。

頒發者一旦發出 lease,則無論接受方是否收到,也無論後續接收方處於何種狀態,只要 lease 不過期,頒發者一定嚴守承諾;另一方面,接收方在 lease的有效期內可以使用頒發者的承諾,但一旦 lease 過期,接收方一定不能繼續使用頒發者的承諾。

Lease 機制具有很高的容錯能力。首先,通過引入有效期,Lease 機制能否非常好的容錯網絡異常。再者,Lease 機制能較好的容錯節點宕機。最後,lease 機制不依賴於存儲。

Lease 機制依賴於有效期,這就要求頒發者和接收者的時鐘是同步的。對於這種時鐘不同步,實踐中的通常做法是將頒發者的有效期設置得比接收者的略大,只需大過時鐘誤差就可以避免對 lease 的有效性的影響。

3. 基於 lease 機制確定節點狀態

在分佈式系統中確定一個節點是否處於正常工作狀態是一個困難的問題。由於可能存在網絡分化,節點的狀態是無法通過網絡通信來確定的。下面舉一個較為具體的例子來討論這個問題。

例 2.3.1:在一個 primary-secondary 架構的系統中,有三個節點 A、B、C 互為副本,其中有一

個節點為 primary,且同一時刻只能有一個 primary 節點。另有一個節點 Q 負責判斷節點 A、B、C

的狀態,一旦 Q 發現 primary 異常,節點 Q 將選擇另一個節點作為 primary。假設最開始時節點 A

為 primary,B、C 為 secondary。節點 Q 需要判斷節點 A、B、C 的狀態是否正常。

首先需要說明的是基於“心跳”(Heartbeat)的方法無法很好的解決這個問題。節點 A、B、C 可以週期性的向 Q 發送心跳信息,如果節點 Q 超過一段時間收不到某個節點的心跳則認為這個節點異常。

上述問題的出現的原因在於雖然節點 Q 認為節點 A 異常,但節點 A 自己不認為自己異常,依舊作為 primary 工作。其問題的本質是由於網絡分化造成的系統對於“節點狀態”認知的不一致。

上面的例子中的分佈式協議依賴於對節點狀態認知的全局一致性,即一旦節點 Q 認為某個節點A 異常,則節點 A 也必須認為自己異常,從而節點 A 停止作為 primary,避免“雙主”問題的出現。解決這種問題有兩種思路,第一、設計的分佈式協議可以容忍“雙主”錯誤,即不依賴於對節點狀態的全局一致性認識,或者全局一致性狀態是全體協商後的結果;第二、利用 lease 機制。

由中心節點向其他節點發送 lease,若某個節點持有有效的 lease,則認為該節點正常可以提供服務。用於例 2.3.1 中,節點 A、B、C 依然週期性的發送 heart beat 報告自身狀態,節點 Q 收到 heart beat後發送一個 lease,表示節點 Q 確認了節點 A、B、C 的狀態,並允許節點在 lease 有效期內正常工作。節點 Q 可以給 primary 節點一個特殊的 lease,表示節點可以作為 primary 工作。一旦節點 Q 希望切換新的 primary,則只需等前一個 primary 的 lease 過期,則就可以安全的頒發新的 lease 給新的primary 節點,而不會出現“雙主”問題。

4. lease 的有效期時間選擇

Lease 的有效期雖然是一個確定的時間點,當頒發者在發佈 lease 時通常都是 將當前時間加上一個固定的時長從而計算出 lease 的有效期。

如何選擇 Lease 的時長在工程實踐中是一個值得討論的問題。如果 lease 的時長太短,例如 1s,一旦出現網絡抖動 lease 很容易丟失,從而造成節點失去 lease,使得依賴 lease 的服務停止;如果 lease 的時長太大,例如 1 分鐘,則一旦接受者異常,頒發者需要過長的時間收回 lease 承諾。例如,使用 lease 確定節點狀態時,若 lease 時間過短,有可能造成網絡瞬斷時節點收不到 lease 從而引起服務不穩定,若 lease 時間過長,則一旦某節點宕機異常,需要較大的時間等待 lease 過期才能發現節點異常。

工程中,常選擇的 lease 時長是 10 秒級別,這是一個經過驗證的經驗值,實踐中可以作為參考並綜合選擇合適的時長。

5. 工程投影

GFS 中的 Lease。GFS 中使用 Lease 確定 Chuck 的 Primary 副本。Lease 由 Master 節點頒發給 primary 副本,持有Lease 的副本成為 primary 副本。

Niobe 中的 Lease。Niobe 中雖然沒有明確說明使用了 Lease 機制,但是通過分析可以發現,這是一個 Lease 機制。Niobe 協議中,也是通過 Lease 機制維持 Primary 副本的選擇,不同的是 Niobe 中的 Lease 是由 Secondary 節點向 Primary 節點發送。在 Niobe 協議中,每個 Secondary 副本都會給 Primary 副本發送 Lease,這個 Lease 的含義是: 在 Lease 時間內,本副本承認你是 Primary 節點。從這裡我們可以看到,niobe 中的 lease 含義也可以理解為:“我承諾在接下來 lease 時間內,我不會 kill 你”。

Chubby 與 Zookeeper 中的 Lease。我們知道 chubby 通過 paxos 協議實現去中心化的選擇 primary 節點(見 2.8.6 )。一旦某個節點獲得了超過半數的節點認可,該節點成為 primary 節點,其餘節點成為 secondary 節點。Secondary節點向 primary節點發送 lease,該 lease 的含義是: “承諾在 lease 時間內,不選舉其他節點成為 primary節點”。除了 secondary 與 primary 之間的 lease,在 chubby 中,primary 節點也會向每個 client 節點頒發lease。該 lease 的含義是用來判斷 client 的死活狀態,一個 client 節點只有只有合法的 lease,才能與 chubby 中的 primary 進行讀寫操作。與 Chubby 不同,Zookeeper 中的 secondary 節點(在 zookeeper 中稱之為 follower)並不向 primary節點(在 zookeeper 中稱之為 leader)發送 lease,zookeeper 中的 secondary 節點如果發現沒有 primary節點則發起新的 paxos 選舉,只要 primary 與 secondary 工作正常,新發起的選舉由於缺乏多數secondary的參與而不會成功。

間接使用 Lease。筆者很難想象,如何在工程上既不使用 Lease 而又實現一個一致性較高的系統。直接實現 lease機制的確會對增加系統設計的複雜度。然而,由於有類似 Zookeeper 這樣的開源的高可用系統,在工程中完全可以間接使用 Lease。藉助 zookeeper,我們可以簡單的實現高效的、無單點選主、狀態監控、分佈式鎖、分佈式消息隊列等功能,而實際上,這些功能的實現都是依賴於背後 zookeeper與 client 之間的 Lease 的。


分享到:


相關文章: