分佈式系統一致性問題與Raft算法(上)

最近在作MIT6.824的幾個實驗,真心以爲每個作分佈式相關開發的程序員都應該去刷一遍(裂牆推薦),確定可以提升本身的技術認知水平,同時也很是感謝MIT可以把這麼好的資源分享出來。程序員

其中第二個實驗,就是要基於raft算法,實現一個分佈式一致性系統。但今天先不說raft算法,而是先討論下什麼是分佈式一致性問題,以及爲何它會難!!下一章再說raft是如何設計從而解決了分佈式共識這一難題。算法

什麼是分佈式一致性問題

首先,什麼是分佈式系統一致性問題?分佈式系統這個詞應該不用多解釋,簡單地說就是由多個節點(一個節點即一臺物理機器或一個進程),異步得經過網絡通信而組成的系統。數據庫

而一致性(Consistency),這個詞在不一樣的場景下有不一樣的含義,比方說你們比較熟的應該是在關係型數據庫中事務的一致性。但在分佈式系統中,一致性的基本含義是對進行進行一個或多個操做指令以後,系統內的其餘成員對這些操做指令的結果可以達成共識,也就是對結果的見解是一致的。安全

舉個例子,比方說有多個客戶端,這些客戶端出於某種緣由,都要對分佈式系統中的變量v賦值,客戶端A發起一個賦值請求修改v=a,客戶端B也發起一個請求修改v=b,等等等。但最終在某一個時刻布式系統內都可以對v的值產生一個共識,好比最終你們都知道v=a。而不會說系統內不一樣節點對這個值有不一樣的見解。網絡

要作到這一點很難嗎?是的,很難。異步

注:一致性這個詞其實包含挺廣的,但這裏特質共識這個意思,因此有時候也會用共識的說法,知道是一個意思就好了。tcp

爲何分佈式一致性問題很難

明白了什麼是分佈式一致性問題以後,咱們再來討論爲何分佈式一致性會很難。分佈式

若是是在單機環境下,實現一致性是很容易作到的,基本上咱們開發的程序都可以作到。但在分佈式環境下,則難度放大了無數倍。由於在分佈式環境下節點間的狀態是經過網絡通訊進行傳輸的,而網絡通訊是不可靠的,無序的,注意這裏的不可靠不是說tcp或udp的那個可靠,而實沒法經過網絡通訊準確判斷其餘節點的狀態。性能

好比A向B發送了一個請求,B沒有迴應。這個時候你沒辦法判斷B是忙於處理其餘任務而沒法向A回覆,仍是由於B就真的掛掉了。設計

順便說一點,分佈式一致的問題每每還具備必定的欺騙性。

它具備必定欺騙性的緣由在於分佈式一致性的問題直觀感覺上每每比較簡單,好比上面的A向B發送請求的問題,咱們不管選擇直接認爲B掛掉,或者選擇讓A不斷進行重試,看上去彷佛都能解決這個問題。但隨着而來的又會有新問題,好比A選擇認爲B掛掉而進行失敗處理,那麼系統繼續無礙運行。但若是B只是由於系統任務繁忙,過一會恢復做業,A就由於自身的選擇破壞了數據的一致性,由於在B斷線期間系統就不一致了。這就又出現了新的問題。

總結起來,就是看似簡單的問題,引入簡單的解,每每又會出現新的問題。然後又繼續在此基礎上「打補丁」,然後又會出現新的問題,不斷循環往復,一個簡單的問題不斷疊加,就變成了超級複雜棘手的問題。就像築堤堵水,水不斷漲,堤壩不斷堆砌,最終到了一個誰也無法解決的境地。

說回剛剛的話題,按照剛剛的例子,其實能夠引出另外一個問題,那就是活性(liveness)和安全性(satefy)的取捨。

活性(liveness)與安全性(satefy)

活性與安全性,這個要怎麼理解呢?

剛剛說到,當A向B發送請求,B沒有及時迴應。但這個時候,A是沒法準確知道B真正的狀態的(忙於其餘任務仍是真的掛掉了),也就是說咱們是沒法作到徹底正確的錯誤檢測

這種時候按照上面的說法,有兩種選擇,

  1. 任務B依舊或者,無限重試,不斷等待。
  2. 直接認爲B掛掉了,進行錯誤處理。

選擇1,破壞了系統的活性,由於在重試的時間內,系統是沒法對外提供服務的,也就是短暫得失活了。

選2呢又破壞了安全性,由於若是B其實沒有掛掉,而這時候從新啓動一個節點負責本來B的工做,那麼此時系統中就會有舊的B節點,和新的B節點。此時舊的節點就稱之爲殭屍節點(Zombie)。而若是在主從分佈的系統,也就是一個leader多個follower的系統中,若是B恰好是leader,那麼這種狀況也被稱之爲腦裂。

能夠發現,liveness和響應速度有關,而satefy又和系統的可用性相關,而且這二者是不可兼得的。

關於這個問題,上世紀Lynch發表的一篇論文《Impossibility of Distributed Consensus with One Faulty Process》,基本上已經闡述了這個定理,也就是FLP impossibility。

FLP impossibility

FLP impossibility說明了這樣一件事,在分佈式或者說異步環境下,即使只有一個進程(節點)失敗,剩餘的非失敗的進程不可能達成一致性。

這個是分佈式領域中的定理,簡稱就是FLP impossibility。

固然全部的定理彷佛都不是那麼好理解,FLP impossibility也是同樣,光是結論聽起來就很是拗口。證實起來那就更加抽象,甚至在論文中也沒有經過例子來論證。由於若是要經過實例來論證,那麼首先就得要先設計N多的分佈式算法,而後再逐一證實這些算法是FLP impossibility。

其實通俗些的理解,那就是說分佈式(異步)環境下,liveness和satefy是魚與熊掌不可兼得。不可能作到100%的liveness同時又兼顧到satefy。想要100%的satefy,那麼liveness又保證不了,這裏面又好像有CAP的影子,不得不說道路都是相通的。

話說回來,既然FLP impossibility已經說死了,異步環境下,即使只有一個進程(節點)失敗,剩餘的非失敗的進程不可能達成一致性,那麼paxos和raft這些算法又是如何作到分佈式異步環境下一致的呢?

柳暗花明

其實FLP impossibility已經爲咱們指明方向了。既然沒法徹底兼得,那天然要放鬆某方面的限制,satefy是不能放鬆的,那天然只能從liveness上下手了。

具體作法上,那就是給分佈式系統加上一個時間限制,其實在前面介紹liveness和satefy的時候,應該就有人能想到了。既然不能一直等待也不能直接任務遠端節點掛掉,那麼折衷一下,在某個時間內不斷重連,超過這個時間,則認爲遠端節點是掛掉就能夠了。

而事實上也正是如此,若是你對zookeeper熟悉,那應該知道zookeeper在選舉leader的時候是不提供服務的,這就是它喪失部分liveness的一個體現。另外一個體現是,性能,由於要經過一個時間段來對遠端節點狀態進行確認,那天然性能會有所降低,這又是不可避免的。

而具體的raft算法,那就等到下一節再說吧。

總結:

  1. 分佈式一致性指的其實就是分佈式異步環境下,要讓多個節點對系統狀態的改變可以達成共識。
  2. 分佈式系統一致性難,難在異步通訊不可靠。由此衍生出了liveness和satefy取捨的問題以及殭屍節點問題,有了FLP impossibility定理。
  3. paxos/raft等算法經過一個安全時間段,能夠在某種程度上實現分佈式系統的一致性。

PS:本篇大部分參考自端到端一致性,流系統Spark/Flink/Kafka/DataFlow對比總結,只是裏面有不少是講流處理系統的。不過一樣是裂牆推薦,反正看過的都說好。

以上~

相關文章
相關標籤/搜索