1. 程式人生 > >線性一致性與全序廣播------《Designing Data-Intensive Applications》讀書筆記12

線性一致性與全序廣播------《Designing Data-Intensive Applications》讀書筆記12

拷貝 原理 隔離 來看 這樣的 失效 一個 syn 分布式系

上一篇聊了聊構建分布式系統所面臨的困難,這篇將著重討論構建容錯分布式系統的算法與協議。構建容錯系統的最佳方法是使用通用抽象,允許應用程序忽略分布式系統中的一些問題。本篇我們先聊一聊線性一致性,以及與線性一致性有關的技術,後續需要了解的分布式協調服務,如:ZooKeeper等,都是基於分布式系統的線性一致性。

1.更強的一致性

大多數分布式數據庫至少提供了最終一致性,這意味著如果停止對數據庫的寫操作並等待一段時間,最終所有讀請求將返回相同的值。但是,這是一個非常弱的一致性保證,所謂的一段時間並不確定。如果寫入一個值,然後立即讀取它,就不能保證讀取到剛才寫入的值。

最終一致性的模型對於應用程序開發人員來說是個大煩惱,當使用只提供弱一致性的數據庫時,開發人員需要意識到它的問題,數據庫可能會有很微妙的錯誤,因為應用程序可能大部分時間都工作得很好。而當系統中有故障(例如網絡中斷)或高並發性時,最終一致性的數據模型將會暴露很多問題。所以數據系統可以選擇提供的更強的一致性模型,但是又會引入新的Trade-off:有更強一致性的系統雖然更容易正確使用,但是它可能比弱一致性的系統的性能更差或容錯性更低,我們需要更好的理解它並且選擇最適合需求的數據模型。

線性一致性

線性一致性的思想很簡單,我們用下面兩幅圖來說明:
技術分享圖片
技術分享圖片

在一個線性系統之中,一定會有某個時間點(開始和結束的寫操作之間),x的值從0變成了1。因此,如果一個客戶端的讀取x時返回了新值1,所有後續的讀取也必須返回新的值。

線性化與串行化

線性化與串行化不同,它不構成事務。因此不能完全保證並發寫的安全性。數據庫可以同時提供串行化和線性化,如兩階段鎖便是可以同時提供串行化與線性化,而序列化的快照隔離不是線性化的。

線性一致性可以解決什麽問題?

  • 分布式鎖和Leader選舉
    單Leader的系統需要確保只有一個Leader,多個Leader會導致腦裂的發生。而Leader選舉的本質是鎖的爭用,每個節點試圖獲取鎖,獲取成功的節點成為Leader。而無論如何,這把鎖必須是線性化:所有節點都必須同意哪個節點擁有鎖,成為Leader

  • 唯一性約束
    唯一性約束在數據庫中很常見:例如,用戶名或電子郵件地址必須唯一地標識一個用戶,而在文件存儲服務中,不能有兩個具有相同路徑和文件名的文件。如果你想為數據寫入執行這一約束(例如,如果兩人試圖同時創建一個用戶或一個具有相同名稱的文件,其中將返回一個錯誤),你需要線性化。

如何實現線性化系統?

線性化意味著:如同一個單拷貝的數據,並對其所有的操作都是原子的。最簡單的答案就是真的只使用一個單一的數據復制。這種方式顯然就失去了容錯性,單一節點出現異常則系統將無法訪問。而使系統容錯的最常用方法是使用副本技術:

  • 單Leader多Follower機制
    在單Leader多Follower機制之中,Leader擁有主副本,Follower在其他節點上維護數據的備份副本。可以選擇從Leader上讀,或同步更新的Follower,可以在這個基礎之上實現線性化系統。

  • 一致性算法
    通過協商一致性協議算法可以防止腦裂和讀取過期數據,通過一致性算法可以實現核心數據線性化的安全存儲。這是ZooKeeper與Chubby等分布式協調服務的基礎算法。

CAP理論與一致性的代價

Eric Brewer在2000年提出CAP理論,簡而言之便是:數據系統必須在一致性、可用性、分區容忍性的三角關系之中有所權衡,任何系統沒有辦法同時滿足三種特性。

所以使用線性化的一致性自然會需要在可用性上做一些妥協, 在單Leader多Follower機制之下,需要滿足線性化一致性的寫入和讀取的客戶端必須連接到Leader。如果Leader產生中斷,仍然可以讀取Follower的數據,但此時就無法保證線性化的要求了。

2.全序廣播

上文已經提到過,可以通過單Leader多Follower機制與一致性算法來實現一個線性化的系統,但是,這裏還有一個很重要的內容我們需要探討:全序廣播
不過先不要著急,咱們先再聊一聊分布式系統之中的時序:

Lamport時間戳

Lamport時間戳是生成因果關系的序列號的一種方法,我們可以通過它理清分布式系統之中操作的順序,Leslie Lamport 在1978年提出。Lamport時間戳的實現很簡單,每個節點有一個唯一計數器標識符,並且每個節點都保存它的計數器。兩個節點有時可能具有相同的計數器值,但在計數器值之中都包含節點id,所以每個計數器值都可以認為是唯一的時間戳。

Lamport時間戳沒有確切的物理時間,但它可以分布式系統之中的事件排序:存在兩個時間戳,一個更大計數器的時間戳是更新的值;如果計數器的值是相同的,一個更大的節點ID是更大的時間戳。下圖展示了Lamport時間戳的工作原理,它能夠符合分布式系統之中的因果關系:
技術分享圖片

但是從Lamport時間戳的總順序來看,無法判斷兩個操作是並發的,還是它們是因果相關的。雖然Lamport時間戳能夠確認操作的因果關系,但是在分布式系統之中仍然存在一些問題:
請考慮一個系統,該系統需要確保用戶名唯一標識用戶帳戶。如果兩個用戶同時嘗試創建具有相同用戶名的帳戶,則其中一個應該成功,另一個應該失敗。顯然,如果兩個相同的用戶名的賬戶創建,選擇具有較低的時間戳的操作成功,因為Lamport時間戳是完全有序的,這種比較是有效的。但是為了確保沒有其他節點在同時在較早的時間創建帳戶,所以節點不得不與其他每個節點通信進行確認。如果出現網絡問題,其他節點中的一個已經失效或無法到達,則系統也將失效。

Lamport時間戳的問題在於:需要收集所有操作之後,操作的總順序才會出現。如果另一個節點有其他操作,在不知道的情況下,無法構造操作的最終順序。

全序廣播

全序廣播的機制是使用:通過單Leader多Follower機制,在Leader節點上對所有操作進行排序,從而決定了整個操作順序,並將操作順序進行廣播。全序廣播可以保證全局知曉信息,而解決Lamport時間戳面臨的問題。但是全序廣播同樣要解決這樣幾個問題:如果吞吐量大於單Leader的處理量,那麽如何擴展系統,以及出現Leader失效的情況,如何進行故障轉移。

全序廣播要求滿足如下兩個屬性總是被滿足:

  • 可靠的交付,沒有消息丟失:如果消息被傳遞到一個節點,它將被傳遞給所有節點。
  • 完全有序傳遞,消息以相同的順序傳遞給每個節點。

一個正確的全序廣播算法必須保證節點和網絡故障時的可靠性和有序性。一旦出現網路分化的現象,算法可以保持重試,仍然保持信息的有序性。全序廣播對於分布式系統來說有十分重要的意義:如果每個消息表示對數據庫的寫入,並且每個副本以相同的順序處理相同的寫入,則副本將保持彼此一致,而各個節點的狀態機也能夠保持一致,可以通過這樣的方式來實現狀態機復制。

3.通過全序廣播實現線性化一致性

全序廣播是異步的:消息保證以固定的順序可靠地傳遞,但不能保證何時傳遞消息(因此存在節點可能落後於其他節點)。而線性化一致性能夠保證:每次讀操作能夠讀到最新值的寫入。我們可以依托於全序廣播,在存儲上實現線性化一致性:

  • 1.將消息append到日誌中,添加要聲明的用戶名。

  • 2.節點通過內存之中的狀態機檢查,如果該用戶名的第一條消息,則用戶名寫入成功。否則,終止該操作。

由於全序廣播保證了,消息是以相同的順序傳遞給所有節點,假設存在並發寫入,所有節點都會達成共識,第一個寫入用戶名的消息。雖然全序廣播可以保證程序的線性寫入,但是假設進行讀操作的節點卻不能保證線性讀取,因為消息傳遞的延遲性,所以讀操作的結果可能是過時的。

當然這裏可以通過返回最新日誌消息的位置,通過查詢位置,等待所有條目需要讀取的條目被寫入,再進行讀操作,便能夠達到讀操作的線性一致性。(在ZooKeeper中通過sync()操作實現),或者可以通過強制讀取Leader節點的副,顯然Leader節點上的數據一定是最新的結果。

小結:

通過全序廣播的線性一致性,我們已經可以實現一個分布式系統的的協調服務了。下一篇將聊一聊分布式系統之中的一致性協議,也是分布式系統最核心的概念,我們怎麽樣能夠讓分布式的節點達成一致性,難者不會,會者不難,我們下一篇見。

線性一致性與全序廣播------《Designing Data-Intensive Applications》讀書筆記12