標籤:ges app images 補齊 cimage 響應 ica 處理 協調器
前文涉及到了很多與Leader相關的演算法,大家有木有想過,王侯將相,寧有種乎,既然Leader這麼麻煩,乾脆還是採用P2P模型吧,來個大家平等的架構。本篇需要和大家探討的就是多副本下實現民主政治的Quorum機制。至於它是怎麼樣解決我們在前文提及的各種問題的,接著這篇文章我們繼續聊聊~~
1. No-Leader機制
有些資料存放區系統放棄了Leader的機制,允許任何副本直接接受使用者的寫操作。(如Amazon的Dynamo,FaceBook的Cassandra,雖然最終FaceBook放棄了Cassandra轉而支援Hbase,但是Uber的強勢介入讓Cassandra後來在開源社區大放異彩。) 每個接受到用戶端寫請求的節點會轉換為一個協調器節點,而協調器節點不強制執行特定的寫入順序。正是這種設計上的差異對資料庫的使用方式與資料模型產生了深遠的影響。
多副本的讀寫
No-Leader機制是怎麼樣消除Leader這個角色的存在的呢?答案也很簡單:多副本讀寫。接下來我們來看一個栗子:
假設我們在資料系統之中採用了三副本的結構,如所示:User 1234 並行地將所有的副本發送給三個儲存節點,並且兩個節點可以接受副本的寫入,但是其中一個節點不線上,所以副本寫入失敗。所以在三個副本中有兩個副本確認寫入成功了:在User 1234收到兩個OK響應之後,User就認為寫入操作是成功的,忽略了一個副本寫入失敗。(當然,不是簡單的就不管這個寫入失敗了,後續會有修複機制來補齊這個副本的資料)
現在假設User 2345開始讀取新寫入的資料。由於一個節點寫入失敗了,所以User 234 可能會得到到期的值作為響應。為瞭解決這個問題,當User 從資料系統之中讀取資料時,它不只是將請求發送到一個副本,而是將讀取請求並行地發送到多個副本節點。User可以從不同節點獲得不同的響應,即來自其他節點的最新值和另一個節點的到期值。這裡通過了版本號碼用於確定哪個值是更新的值。
副本修複
No-Leader機制導致了資料系統之中可能存在大量到期的值,所以一個節點怎麼來修複自身的副本來擷取最新值的過程我們就稱之為副本修複,No-Leader機制也是通過這樣的方式來達到最終一致性的。通常會有這樣幾種方式:
讀修複
當使用者並行讀取多個節點時,它可以擷取到其他到期的值的響應。所以使用者會發現其中有些節點擁有到期的值,這時使用者可以主動將新值寫入該節點。這種方法稱之為讀修複。
反熵過程(其實是一個物理學概念)
每個資料存放區節點都會有一個後台進程,不斷的比對自己的副本與其他節點副本的差異,發現自己擁有到期的值之後,會主動修複自己到期的副本。與基於寫入順序日誌不同,這種反熵過程不以任何特定的順序複製寫操作,並且在複製資料之前可能會有顯著的延遲。
2. Quorum機制
上文之中提及的例子在三個副本中的兩個之上寫入成功,我們認為寫操作成功了。但是如果三個副本只有的一個副本寫入成功了?這時的寫操作是否是成功的呢?
答案是否定的?這裡其實就是簡單的鴿巢原理,這裡我不做數學證明了,大家有興趣的可以自行證明一下。
假設有n個副本,每次寫操作必須由w個節點確認為成功,每個讀操作讀取r個節點。(在上文的例子中,n=3,w=2,r=2)。只要w + r > n,如果讀和寫操作的總次數大於n,那麼讀和寫操作必然至少有一個副本是相同的,也就是讀操作必然可以讀到最新寫操作的資料。這被我們稱之為:Quorum機制,每次讀寫都需要達到法定人數。
通常 n、w和r通常是可配置的,根據您的需要來修改這些數字。一個常見的選擇是使n為奇數(通常為3或5),並設定w=r=(n + 1)/ 2 。如所示,如果w < n,如果有n - w個節點不可用,我們仍然可以處理寫操作。同樣的如果r<n,如果有n - r個節點不可用,我們仍然可以處理讀操作。而如果小於所需的w或r節點可用,則寫或讀操作就會返回錯誤。
- n=3,w=2,r=2,我們可以容忍一個停用節點。
- n=5,w=3,r=3,我們可以容忍兩個停用節點。
高可用與Hinted handoff
Quorum機制實現了最終一致性的模型,但是在可用性上還是有一些極端情況,沒法很好處理。如:出現網路抖動時,但是可能系統仍然有許多正常工作的節點。但是副本應該被寫入的n個節點發生網路問題,導致了會少於w或r個成功的讀寫操作,由於不能達到法定的人數,讀寫操作都會失敗。所以這時候資料庫系統的設計者面臨權衡取捨,能不能通過一些機制,實現更好的可用性呢?
所以這種情況下,我們就可以利用Hinted handoff了(原諒我翻譯不好)。這種方式是怎麼樣實現的呢?寫和讀操作仍然需要w和r成功的響應,但是可以不強制一定要寫如指定的n個節點 (這個涉及到一致性雜湊,資料分布的知識,暫時要是理解不了,我後續會有專門的專題來寫這個內容,可以先放一放。) 打個比方說,如果你把自己鎖在門外,你可能會敲鄰居的門,問你是否可以暫時呆在他們的沙發上,一旦你找到鑰匙了,你就自己回家了。所以其他節點可以暫存本應該放在另一個節點上的副本,一旦網路中斷被修複,其他節點就會把副本轉交給主人節點。
所以這種模式既保證了不違反Quorum機制,也大大提高了系統的可用性,被No-leader資料系統廣泛採用。
3 寫入衝突與Quorum機制
同樣的Quorum機制的設計本身就可以允許並發讀寫操作,並容忍網路中斷與高峰延遲。但是這也必然會帶來一致性問題,我們來看下面這個例子:
,有兩個Client A與B,同時寫入關鍵字X在一個三副本的資料存放區系統之中。Node 1接收來自A的寫入,但由於網路中斷而從未接收來自B的寫入。Node 2首先接收來自A的寫入,然後接收B寫入。而Node 3則是首先接收來自B的寫入,然後接收A的寫入。Node 2認為X的最終值是B,而其他Node認為最終值是A.
在這樣的情境下如何仲裁寫入結果成為了一個大問題,思路和我們之前提到的類型:
合并“happen-before"使用一個單一的版本號碼來捕捉操作之間的依賴關係,但這不足以解決當有多個副本並行寫入的情況。相反,我們需要使用每個副本的版本號碼以及每個鍵。每個副本在處理寫時遞增自己的版本號碼,並跟蹤從其他副本中看到的版本號碼。此資訊指示要覆蓋哪些值以及作為兄弟版本儲存著哪些值。而所有副本的版本號碼的集合稱為版本向量。版本向量從資料節點發送給用戶端,所以版本向量讓我們可以區分覆蓋寫與發並行寫操作。
4. 小結
好了,到此為止我們終於總結完整了分布式系統之中的副本機制。從Leader-Follower 機制到多Leader機制,最後到No-Leader的機制,並且詳細總結了各個機制的實現細節與優缺點,希望大家閱讀完之後也能有所收穫。
P2P結構與Quorum機制------《Designing Data-Intensive Applications》讀書筆記8