算法:FLP不可能理論。

FLP impossibility背景

FLP Impossibility(FLP不可能性)是分佈式領域中一個非常著名的結果,該結果在專業領域被稱爲“定理”,其地位之高可見一斑。該定理的論文是由Fischer, Lynch and Patterson三位作者於1985年發表,之後該論文毫無疑問得獲得了Dijkstra獎。

順便要提一句的是,Lynch是一位非常著名的分佈式領域的女性科學家,研究遍佈分佈式的方方面面,對分佈式領域有着極其卓越的貢獻,其著有<<Distributed Algorithms>>一書,書中有非常嚴謹而簡潔的邏輯討論了許許多多的分佈式算法。

FLP給出了一個令人吃驚的結論:在異步通信場景,即使只有一個進程失敗,也沒有任何算法能保證非失敗進程達到一致性!

因爲同步通信中的一致性被證明是可以達到的,因此在之前一直有人嘗試各種算法解決以異步環境的一致性問題,有個FLP的結果,這樣的嘗試終於有了答案。

FLP證明最難理解的是沒有一個直觀的sample,所有提到FLP的資料中也基本都回避了sample的要求。究其原因,sample難以設計,除非你先設計幾種一致性算法,並用FLP說明這些算法都是錯誤的。

系統模型

任何分佈式算法或定理,都尤其對系統場景的假設,這稱爲系統模型。FLP基於下面幾點假設:

  • 異步通信
    與同步通信的最大區別是沒有時鐘、不能時間同步、不能使用超時、不能探測失敗、消息可任意延遲、消息可亂序
  • 通信健壯
    只要進程非失敗,消息雖會被無限延遲,但最終會被送達;並且消息僅會被送達一次(無重複)
  • fail-stop模型
    進程失敗如同宕機,不再處理任何消息。相對Byzantine模型,不會產生錯誤消息
  • 失敗進程數量
    最多一個進程失敗

在現實中,我們都使用TCP協議(保證了消息健壯、不重複、不亂序),每個節點都有NTP時鐘同步(可以使用超時),純的異步場景相對比較少。但隨着只能終端的發展,每個手機會爲省電而關機,也會因爲不在服務區而離線,這樣的適用場景還是存在。

我們再衡量一個分佈式算法是否正確時有三個標準:

  • Termination(終止性)
    非失敗進程最終可以做出選擇
  • Agreement(一致性)
    所有的進程必須做出相同的決議
  • Validity(合法性)
    進程的決議值,必須是其他進程提交的請求值

終止性,描述了算法必須在有限時間內結束,不能無限循環下去;一致性描述了我們期望的相同決議;合法性是爲了排除進程初始值對自身的干擾。

一個Sample

假設有A、B、C、D、E五個進程就是否提交事務爲例,每個進程都有一個隨機的初始值提交(0)或回滾(1)來向其他進程發送請求,進程自己必須接收到其他進程的請求後才能根據請求內容作出本地是提交還是回滾的決定,不能僅根據自己的初始值做出決定。如果所有的進程都做出相同的決定,則認爲一致性達成(Validity屬性);根據前面的系統模型,允許最多一個進程失敗,因此一致性要求要放鬆到允許非失敗進程達成一致。當然,若有兩個不同的值被不同的進程選擇,則認爲無法達成一致。

現在目標是要設計這樣一個算法,保證符合上述三個屬性,並允許最多一個進程失敗。

假如我們設計一個算法P,每個節點根據多數派表決的方式判斷本地是提交還是回滾:

假如C收到了A、B的提交申請,收到了D的回滾申請,而C本身也傾向於回滾,此時,提交、回滾各有兩票,E的投票決定着C的最終決議。而此時,E失敗了,或者E發送給C的消息被無限延遲(無法探測失敗),此時C選擇一直等待,或者按照某種既定的規則選擇提交或失敗,後續可能E正常而C失敗,總之,導致C沒有做出最終決策,或者C做了最終決策失敗後無人可知。稱所有進程組成的狀態爲Configuration,如果一系列操作之後,沒有進程做出決策稱爲“不確定的”Configuration;不確定Configuration的意思是,後續可能做出提交,也可能做出回滾的決議。

相反,如果某個Configuration能準確地說會做出提交/回滾的決議,則稱爲“確定性”的Configuration(不確定/確定對應於原論文中的bivalent/univalent)。如果某個Configuration是確定的,則認爲一致性是可以達成。

對上述算法P,可能存在一種極端場景,每次都構造出一個“不確定”的Configuration,比如每次都是已經做出決議的C失敗,而之前失敗的E復活(在異步場景中,無法真正區分進程是失敗,還是消息延遲),也就是說,因爲消息被延遲亂序,導致結果難以預料!

而FLP證明也是遵循這個思路,在任何算法之上,都能構造出這樣一些永遠都不確定的Configuration,也就沒有任何理論上的具體的算法,能避免這種最壞情況。

Paxos爲什麼可以?

此時我們會馬上想到,Paxos算法的場景比FLP的系統模型還要鬆散,除了異步通信,Paxos允許消息丟失(通信不健壯),但Paxos卻被認爲是最牛的一致性算法,其作者Lamport也獲得2014年的圖靈獎,這又是爲什麼?
其實仔細回憶Paxos論文會發現,Paxos中存在活鎖,理論上的活鎖會導致Paxos算法無法滿足Termination屬性,也就不算一個正確的一致性算法。Lamport在自己的論文中也提到“FLP結果表明,不存在完全滿足一致性的異步算法...",因此他建議通過Leader來代替Paxos中的Proposer,而Leader則通過隨機或其他方式來選定(Paxos中假如隨機過程會極大降低FLP發生的概率)。也就是說Paxos算法其實也不算理論上完全正確的,只是在工程實現中避免了一些理論上存在的問題。但這絲毫不影響Paxos的偉大性!

定理證明

一些定義

原文雖然字數不多(只有6頁)但卻給出了大量的概念定義,我們儘量簡化爲下面幾個:

  • 消息隊列:
    假定存在一個全局的消息隊列,進程可以發送消息,也可以在其上接收消息。
    send/receive:send(p,m)是指給進程p發送消息m,只是放入隊列,稱”發送“,如果消息被p接收,成送達(delivery);receive(p):接收發送給p的消息,若沒有則返回空
    消息隊列實際上是模擬了異步通信,即消息會被延遲、亂序
  • Configuration:前面已經提到,所有進程的狀態集合,進程的狀態包括初始值、決議值、消息隊列的內容
    初始Configuration:各個進程初始值是隨機的、消息隊列爲空、決議爲空的開始狀態
  • 事件e=(p,m)
    事件代表給某個進程發送消息,並且消息已經送達。正是因爲執行了某個事件,導致Configuration變化爲另一個Configuration
  • 事件序列run
    一連串順序執行的事件序列稱爲一個run
  • 可達Configuration
    如果某個Configuration A執行了一個run得到另一個Configuration B,則稱B從A可達

接下來通過三個引理證明了最終的FLP結果。

引理1(連通性)

【把所有的進程P分成兩個不相交的集合P1,P2,有兩個run R1,R2,如果先給P1應用R1,再給P2應用R2與先給P2應用R2,再給P1應用R1,對P的Configuration C來說得到的結果是一致的(結果顯而易見,不再羅列證明)】

引理2(初始Configuration不確定性)

【對任何算法P都存在一個不確定性的初始Configuration(從該Configuration即可到達提交也可到達回滾,參考上面smaple)】

這個引理主要是爲了說明,不是所有的決議結果都有初始值決定。如果所有進程的初始值都爲“提交”,則決議值肯定爲“提交”;相反若都爲“回滾”則決議爲“回滾”,但如果初始值隨機化後,因爲消息的延遲,最終的決議值就可能是“提交”也可能是“失敗”(不確定性),這個引理也揭示了異步消息的本質特徵。

反證法,假如所有的初始Configuration都是確定性的,即一些決議值必定爲“提交”,而另一些一定是“回滾”。如果兩個Configuration只有一個進程的狀態有差別,則稱爲相鄰,把所有Configuration按相鄰排成一個環,則必定存在一個Configuration C0和C1相鄰,並且C0是決議“提交”,C1決議“回滾”。

假如某一個Run R導致C1最終的決議值爲“回滾”,根據系統模型,允許最多一個進程失敗,我們就假設C0和C1的連接進程P發生失敗。刨除P後,C0和C1的內部狀態應該完全一致,這樣Run R也可應用於C0,也會得到與C1同樣的決議結果:“回滾”。這與C0是“提交”的結果矛盾,因此,必定存在“不確定”的初始Configuration。

證明嚴密而巧妙,其中構建相鄰環和基於最多一個進程失敗的假設是關鍵。構建環的方法還會在後續證明中用到。

引理3(不可終止性)

【從一個“不確定”的Configuration執行一些步驟(delivery消息)後,仍可能得到一個“不確定”的Configuration】

這一點我們已經從前面的Sample看到了,下面是要證明對任何的分佈式算法P都存在這樣的不可終止性。爲了證明方便,再定義一些用到的符號:

證明的正規化

假設Configuration X是“不確定”的,e=(p,m)是可應用於X的事件,C從X可達且沒有應用e的Configuration集合;D=e(C)是對C應用事件e得到的Configuration集合。則D中一定包含一個“不確定”的Configuration。

非常不可思議,e已經應用到了C,雖然進程p已經接受了消息m,得到的Configuration還可能是不確定性的。如Sample所示,在異步環境中的確可以發生這樣的情況。

還是反證法,證明D中的Configuration都是“確定性”的。

 證明D中既包含決議爲”提交“的Configuration,也包含決議爲”回滾“的Configuration。也即證明D中的Configuration不是單值決議。

設E0、E1分別是X中的0-valent(提交)和1-valent(回滾),因爲X是”不確定“的,因此E0、E1必存在。假如E0屬於C,即沒有應用事件e,則令F0=e(E0),則F0屬於D;若E0已經應用了e,則在到達E0的過程中,存在D中的F0,E0從F0可達。畫一張圖說明以下:

因爲D是”確定“的,E0是0-valent的,無論E0從F0可達,還是F0從E0可達,則F0必定是0-valent的。同樣對E1,也可到的一個1-valent的F1。這就證明了,D包含着0-valent和1-valent。

若D是”確定“的,則導出一個矛盾

如果一個Configuration採取了一個步驟(比如接收一個事件)而產生另一個Configuration,則稱二者爲鄰居。根據相鄰環的構建方法,在C中存在C0、C1,二者是鄰居,並且C0是0-valent的,C1是1-valent的。

Di=e(Ci),i=0,1,是i-valent的。假設C1=e'(C0),e'=(p',m'):

(1)如果p≠p',則D1=e'(D0),根據連通性會導出一個矛盾(從D0會到D1,這顯然是不可能的):

(2)那必然是p=p',先看下圖:

我們考慮構造一個Run R,從C0開始,在其中進程p沒有采取任何動作(比如,根據假設,進程p失敗了),則到達Configuration A;

因爲,R對進程p沒有任何作用,故R可應用於D0、D1,分別得到E0、E1(因爲根據假設D是”確定“的,E0和E1也分別就是0-valent和1-valent)。根據連通性,如果對A連續應用e',e, 則會到達E1;如果對A應用e,則會到達E0。也就是說A是”不確定“的。這與C0是確定的Configuration矛盾,這導致最初的假設D是”確定的”錯誤,因此D是“不確定”的。

這個證明非常巧妙,其核心是根據連通性,構造了一個“不確定”的Configuration。

總結

FLP的證明非常簡潔而嚴謹,這應該是Lynch一貫的作風。看到FLP想起數學上著名的1+1問題的一個例子,1+1這個著名的問題唄關注時,大多數中國人只有初等數學的水平,每天都有很多人給中科院數學研究所寫信,確信自己解決了這個看起來非常簡單的問題。信非常多,但多數證明是錯誤的,不看又怕漏掉一些正確的,工作人員非常辛苦。

後來,有人給出了一個證明,對1+1問題,不可能使用初等數學去解決,這樣那些成麻袋的信就無需再看了,當然那些人對1+1的熱情也隨之被澆滅。最殘忍的是自己認識到“就自己目前掌握的知識根本無法解決這個問題,不是是否努力的問題”。

FLP對此也有類似的影響,但FLP只是理論上存在不可終止性,實際場景中,連續發生不可終止的概率是很低的,可以說爲0.至少,FLP證明了異步通信的最壞情況。

非常感謝Ken Birman教授,正是他不厭其煩的講解,才使我對此有較深入的瞭解。

參考資料

  • Impossibility of Distributed Consensus with One Faulty Process
  • http://the-paper-trail.org/blog/a-brief-tour-of-flp-impossibility/comment-page-1/#comment-102212
  • Lynch的大作:<<Distributed Algorithms>>
  • FLP_and_Paxos.pdf(Ken Birman)
  • Ken Birman教書的網站:http://www.cs.cornell.edu/ken/

Origin

在處理和分析數據時,最理想的環境是這樣的:
一臺有無限存儲和計算能力的“超級計算機”,可以提供無窮大的存儲容量,並且可以將計算時間降低至無窮小。


《銀河系漫遊指南》中全宇宙全時空第二強的計算機“深思”,花費750萬年時間,計算出了“宇宙、生命及萬物 ”終極問題的答案:42

這樣一臺“超級計算機”在現實世界中並不存在。計算機的存儲和計算能力始終要受到客觀物理規律的限制。在可預見的將來,單位存儲單元上無法存儲超量的數據;而在運行計算任務時,由於芯片計算能力是有限的,當計算需求超過瞬時計算能力時,往往會發生排隊現象。爲了解決大量數據的存儲和計算能力不足的問題,我們有兩種選擇:

縱向擴展

即升級硬件設備。通過如升級存儲量更高的硬盤、單位時間運算速度更高的芯片,可以爲計算機提升性能和存儲量,來解決上述問題。但這種硬件的升級會受到計算機本身架構的侷限,同時進一步升級所需要的成本會快速上升,從而使得升級硬件的邊際效益快速下降。此外,升級所用的硬件依然具有其自身的侷限性,並不能徹底解決上述的問題。

橫向擴展

使用多臺普通計算機來模擬“超級計算機”。也就是使用多臺機器各自並行地進行存儲和計算這種方式進行模擬。使用這種方式構建的計算機系統叫做分佈式系統,它具有以下三個特點:一組計算機、通過網絡傳遞信息、協調計算機的行爲。通過這種方式,我們可以近似地獲得無限的存儲和計算能力,解決單機下存儲和計算的侷限。
作爲通過網絡連接的多臺計算機系統,分佈式系統的設計目標一般包括:

  • 擴展性 :增加機器不改變或極少改變系統行爲,並能獲得近似線性的性能提升;
  • 性能 :指分佈式系統進行服務時的延時和吞吐率是滿足用戶需要的;
  • 可用性 :分佈式系統的核心需求,表示分佈式系統是否處於整體可服務並且一直可服務的狀態;
  • 容錯性 :系統發生錯誤時,系統有對錯誤進行規避和恢復的能力。

通過搭建合理的系統架構,進行恰當的數據管理,分佈式系統是可以滿足以上的設計目標的。一套順暢運行的分佈式系統可以在很大程度上滿足大量數據的存儲和計算需求。儘管如此,任何事情都需要付出代價。分佈式的方式不僅增加了工程複雜性,甚至在理論上會出現不可逾越的障礙。本文將根據GeneDock的分佈式實踐經驗對這些優缺點進行必要的探討。

Problem

爲了實現分佈式系統的設計目標,我們需要先了解分佈式系統實現過程中需要克服的問題和困難。一套分佈式系統的主要物理要素包括節點的數目以及節點間的距離。僅這兩點的更改就會引入以下限制:

  • 節點數增加會導致系統整體出錯概率增大
  • 節點數增加會導致節點間通信量增加
  • 節點間距離增加會導致系統最優(或部分)性能變差

拋開工程的視角,僅從理論層面看,分佈式系統也存在着如下三類視角的系統劃分:

  • 保持一致 :系統中相關數據間的邏輯關係應當是正確和完整的。極端情況下,從系統中任意部分讀取而獲得的數據應當都爲最近寫入的數據;
  • 處理失效 :分佈式系統可能出現的失效狀況有三類:節點失效、網絡分區失效、拜占庭失效。極端情況下,系統的執行和操作不會受到任何系統內部失效的影響;
  • 時鐘同步 :分佈式系統有兩種模型:同步系統和異步系統。同步系統會確保所有執行過程的步調一致,且各執行過程有精確的時鐘。即任意處理過程能夠得到精確的執行流程的偏序關係,也就意味着每個處理過程和通信都在有限的時間內進行。異步系統則相反,沒有任何時序性保證。即各處理過程是完全以自己的節拍在運行,不存在有效的同步時鐘,也意味着過程間的通信延時可能會趨於無窮大。

針對物理層面和理論層面存在的種種問題,分佈式系統研究人員希望找到這些問題的答案:是否可以通過硬件技術和軟件算法來克服困難,實現一個理想的或接近理想的分佈式系統,以達成模擬那臺“超級計算機”的設計目標?

Impossibility

不幸的是,在實際應用中,理想的分佈式系統實際是不可能實現的。

圖爲歷史上最著名的第一類永動機“魔輪”。人類花費超過500年的時間才學習到:Something is impossible.
P.S. “中華宇宙能源超磁能機車”——即使在永動機歷史上也是非常“出彩”的。可以去百度永動機貼吧長長見識 (╯□╰)
爲什麼?我們可以從一致性問題(Consensus Problem)——也就是分佈式系統必須解決的一個問題出發,同時考慮其他設計目標,看看可以推導得到什麼樣的結果。一致性問題(Consensus Problem)是指:

  • 一致(Agreement) :每個正確的執行過程應該在相同的值上達成一致;
  • 完整(Integrity) :每個正確的執行過程最多隻能決定一個值。如果它決定了某個值的話,這個值一定是被某個執行過程提出的;
  • 終止(Termination) :所有的執行過程最終會做出一個決定;
  • 正確(Validity) :如果所有正確的執行過程提出了相同的值V,那麼所有正確的執行過程都會決定值V。

基於以上要求,可以推導出在分佈式系統領域非常重要的定理:

FLP不可能性
在假設網絡可靠、計算節點只會因崩潰而失效的最小化異步模型系統中,仍然不存在一個可以解決一致性問題的確定性算法僅這一條定理就已經打碎了我們模擬“超級計算機”的幻想。不過從務實的角度考慮,雖然不能實現理想的分佈式系統,但我們是否可以通過對系統主要設計指標進行一定的妥協,來設計出一個理論上可行的、可以滿足實際需求的分佈式系統呢?

Trade-off

幸運的是,由Eric Brewer等人提出的 CAP定理 已經爲我們回答了這個問題。 CAP定理 的一個表述是:

CAP定理
分佈式計算系統不可能同時確保一致性、可用性和分區容忍性。
  • 一致性(Consistency) :所有節點在同一時刻能夠看到同樣的數據,也即“強一致性”;
  • 可用性(Availability) :確保每個請求都可以收到確定其是否成功的響應;
  • 分區容忍性(Partition tolerance) :因爲網絡故障導致的系統分區不影響系統正常運行。

這也就意味着,我們雖然不能使某個分佈式場景同時滿足三個性質,但可以使之同時滿足三個中的兩個。更進一步說,對於包含多個分佈式場景的分佈式系統,我們甚至可以在三個性質的程度上進行適當的權衡。

CAP權衡方案

我們把解決一致性問題(Consensus Problem)的算法叫做一致性算法(Consensus Algorithm)或者一致性協議(Consensus Protocol)。CAP定理能夠將這些一致性算法的集合進行歸類:

  • C+A :以2階段提交(2 phase commit)爲代表的嚴格選舉協議。當通信中斷時算法不具有終止性(即不具備分區容忍性);
  • C+P :以Paxos、Raft爲代表的多數派選舉算法。當不可用的執行過程超過半數時,算法無法得到正確結果(即會出現不可用的情況);
  • A+P :以Gossip協議爲代表的衝突解決協議。當網絡分區存在和執行過程正確時,只能等待分區消失才保持一致性(即不具備強一致性)

基於CAP定理,我們需要根據不同場景的不同業務要求來進行算法上的權衡。對於分佈式存儲系統來說,網絡連接故障是無法避免的。在設計系統時不得不考慮分區容忍性,所以我們實際上只能在一致性和可用性之間進行權衡。
強一致性與可用性的矛盾會導致十分令人頭疼的抉擇。在實際情況中,對於不是那麼重要的數據的存取操作,往往會調低一致性來增加可用性。如GeneDock的賬戶信息管理數據,是以最終一致性的方案分發到各個業務域的,這樣既滿足了各域業務API的性能需求,又使得跨域的賬戶信息同步功能得以實現。當然,對於敏感的元數據信息,GeneDock採取的則是強一致性的方案。

知名分佈式系統的主場景設計權衡

特別值得一提的經典設計範例是阿里巴巴的OceanBase系統。它將數據分爲了冷數據和熱數據兩個不同的場景。對於冷數據,規定只讀不寫。這樣就不需要處理分佈式寫操作帶來的一致性問題,只需保證可用性和分區容忍性即可(即AP場景)。而對於新增的熱數據,由於用戶需要頻繁訪問,所以採取不同的服務器分片進行服務,本地讀寫的模式,不需要考慮網絡分區的問題(即CA場景)。通過對CAP定理的深刻理解和靈活運用,構建出了滿足高併發讀寫、處理海量金融數據的分佈式數據庫。

Summary

在計算的世界裏,一切都是有代價的。 我們必須根據業務實際場景,在關鍵的業務指標中進行權衡,進而決定合適的解決方案。必須承認,很多系統聲稱能夠解決的問題其實已經被理論證明是不可實現的,這也客觀上要求用戶在選擇雲服務提供商的時候一定要擦亮眼睛,不能被過度的宣傳所誤導。

GeneDock的分佈式系統解決方案是在深入考量了生物信息分析領域的實際需求,對許多問題做了艱難權衡之後才確定下來的,已經經受住了近兩年的大規模商業計算和存儲業務的考驗。無論是在針對計算量巨大的全基因組分析或BLAST等分析任務,還是在大規模基因數據的存取及傳輸場景中,GeneDock對解決方案都進行了精心的設計和實現,確保任務運行的穩定性、數據存儲的可靠性和數據傳輸的正確性,同時使整體系統運行結果準確一致。

參考資料

發佈了116 篇原創文章 · 獲贊 148 · 訪問量 85萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章