CAP理論

CAP理論在互聯網界有着廣泛的知名度,知識稍微寬泛一點的工程師都會把其作爲衡量系統設計的準則。大家都非常清楚地理解了CAP:任何分佈式系統在可用性、一致性、分區容錯性方面,不能兼得,最多隻能得其二,因此,任何分佈式系統的設計只是在三者中的不同取捨而已。

事實上,讓人吃驚的是,CAP在國外的響力完全不如所想,相反還伴隨着諸多的爭論。下面我們系統地闡述一下CAP的來龍去脈。

1.CAP的歷史

1985年Lynch證明了異步通信中不存在任何一致性的分佈式算法(FLP Impossibility)的同時,人們就開始尋找分佈式系統設計的各種因素。一致性算法既然不存在,但若能找到一些設計因素,並進行適當的取捨以最大限度滿足實現系統需求成爲當時的重要議題。比如,在CAP之前研究者就已經發現低延遲和順序一致性不可能同時被滿足【8】。
2000年,Eric Brewer教授在PODC的研討會上提出了一個猜想:一致性、可用性和分區容錯性三者無法在分佈式系統中被同時滿足,並且最多隻能滿足其中兩個!
這個猜想首次把一致性、可用性和分區容錯三個因素提煉出來作爲系統設計的重要特徵,斷言用此三者可以劃分所有的分佈式系統,並指明這三個特徵之間的不可能性關係。Brewer猜想比單純的“低延遲和順序一致性不能被同時滿足”的結論更具體,對實際系統的構建也更具有可操作性!
Brewer教授當時想象的分佈式場景是webservice,一組websevrice後臺運行着衆多的server,對service的讀寫會反應到後臺的server集羣,並對CAP進行了定義:
  • C(一致性):所有的節點上的數據時刻保持同步
  • A(可用性):每個請求都能接受到一個響應,無論響應成功或失敗
  • P(分區容錯):系統應該能持續提供服務,即使系統內部有消息丟失(分區)
高可用、數據一致是很多系統設計的目標,但是分區又是不可避免的事情:
  • CA without P:如果不要求P(不允許分區),則C(強一致性)和A(可用性)是可以保證的。但其實分區不是你想不想的問題,而是始終會存在,因此CA的系統更多的是允許分區後各子系統依然保持CA。
  • CP without A:如果不要求A(可用),相當於每個請求都需要在Server之間強一致,而P(分區)會導致同步時間無限延長,如此CP也是可以保證的。很多傳統的數據庫分佈式事務都屬於這種模式。
  • AP wihtout C:要高可用並允許分區,則需放棄一致性。一旦分區發生,節點之間可能會失去聯繫,爲了高可用,每個節點只能用本地數據提供服務,而這樣會導致全局數據的不一致性。現在衆多的NoSQL都屬於此類。
CAP的出現彷彿是一盞明燈,它揭露了分佈式系統的本質,並給出了設計的準則,而這正是1985年以來人們正在尋找的東西!所以CAP在當時的影響力是非常大的!

2. CAP被上升爲定理

2002年,Lynch與其他人證明了Brewer猜想,從而把CAP上升爲一個定理【2】。但是,她只是證明了CAP三者不可能同時滿足,並沒有證明任意二者都可滿足的問題,所以,該證明被認爲是一個收窄的結果。
Lynch的證明相對比較簡單:採用反正法,如果三者可同時滿足,則因爲允許P的存在,一定存在Server之間的丟包,如此則不能保證C,證明簡潔而嚴謹。
在該證明中,對CAP的定義進行了更明確的聲明【2】:
  • C:一致性被稱爲原子對象,任何的讀寫都應該看起來是“原子“的,或串行的。寫後面的讀一定能讀到前面寫的內容。所有的讀寫請求都好像被全局排序。
  • A:對任何非失敗節點都應該在有限時間內給出請求的迴應。(請求的可終止性)
  • P:允許節點之間丟失任意多的消息,當網絡分區發生時,節點之間的消息可能會完全丟失
該定義比Brewer提出的概念清晰了很多,也顯得更加正式化!

3.前所未有的質疑

當國內工程師對CAP癡迷的時候,國外的工程師和研究者對CAP提出了各種質疑,紛紛有用反例證明着CAP在各種場合不適用性,同時挑戰着Lynch的證明結果!
縱觀這些質疑,基本都是拿着一個非常具體的系統,用CAP的理論去套,最後發現要麼CAP不能Cover所有的場景,要麼是CAP的定義非常模糊,導致自相矛盾!一句話,把CAP接地氣是非常困難的!
你是否看了CAP的概念定義後還是感覺很模糊?如果是,你並不孤獨,有很多人都是如此!
CAP沒有考慮不同的基礎架構、不同的應用場景、不同的網絡基礎和用戶需求,而C、A、P在這些不同場景中的含義可能完全不同,這種無視差異化的定義導致了非常大的概念模糊,同時也變成CAP被質疑的源頭!

3.1 質疑1:概念混亂,廢話一堆,不能作爲定理

在論文【4】中,作者對CAP發起了強烈的挑戰,強烈譴責了CAP模糊不一致的概念:
  1. 在CA中的C代表的是本地一致性;CP中的代表的是全局一致性,AP中直接沒有C;這些C的含義在不同的場景根本就不同
  2. 終端用戶agent該不該引入到CAP中?CAP到底是說一個agent的多次更新,還是多個用戶的一次更新?沒有agent參與的系統談什麼一致性?
  3. 如果分區發生在系統內部(水平分區),對agent而已並沒有影響;若分區發生在agent與系統間(垂直分區),這種情況對DNS系統架構的可用性根本沒有任何影響;但對銀行事務架構卻有巨大影響。也就是說,可用性、分區容錯,是兩個相關切無法獨立切分的概念
一句話:CAP說了一些永遠不存在的廢話!作爲一個嚴格的數學定理,一定要概念清晰並且可自證明,CAP顯然不具備這個條件,並聲稱“絕不承認其爲一個定理”!
【4】的作者對相對論有相當的理解,從相對論來看,每個節點都只知道自己的結果,永遠無法得知其他節點的情況,系統整體是否一致我怎麼會知道?
並且作者對一致性、可用性歸結爲一個非常深刻的見解:一切都是時間視圖!多長時間返回結果算可用?多長時間返回認爲不可用?多長時間數據同步算一致?因此,一切的本質是時間!
根據時間特性和相對論,作者提出了一個獨創的promise系統模型,每個節點都對自己的行爲在有限時間內進行承諾,其他節點根據這個承諾和自己的狀態決定本地如何處理。。。
作者還上傳了自己的筆記拍照,我大體看了下,基本上是構建了一個基於時間同步的有限狀態機,實際上Lynch早就證明,在同步環境的一致性是可以達到的!

3.2 質疑2:不適用於數據庫事務架構

【6】的作者,把詳細地列舉了分佈式事務中可能的分區情況,比如說應用因爲更新一些錯誤的數據而導致失敗,此時無論使用什麼樣的高可用方案都是徒勞,因爲數據發生了無法修正錯誤!作者還列舉了其他一些情況,雖然分區發生但無法保持高可用。這就說明了CAP並不能不被用來完全解釋數據庫事務架構!
作者還建議,應該放棄分區容錯,因爲在局域網中分區很少發生;而在廣域網中,有各種備選方案,導致實際上的分區也較少發生。

3.3 質疑3:應該構建不可變模型避免CAP的複雜性

【7】的文章標題就是錘死CAP,作者對CAP的不屑溢於言表!
作者認爲CAP的困境在於允許數據變更,每次變更就得數據同步,保持一致性,這樣系統非常複雜。
他認爲數據就是客觀存在的,不可變,只能增、查。傳統的CURD變爲CR。這個概念非常類似Cassandra中的順序寫的概念,任何的變更都是增加記錄。通過對所有記錄的操作進行合併,從而得到最終記錄。
因此,作者認爲任何的數據模型都應該抽象爲:Query=Function(all data),任何的數據試圖都是查詢,查詢是對全體數據施加了某個函數的結果。這個定義清晰簡單,完全拋棄了CAP那些繁瑣而又模糊的語義。因爲每次操作都是隊所有數據進行全局計算,也就沒有了一致性問題!
有這樣的系統嗎?有,Hadoop便是!作者認爲,Hadoop的HDFS只支持數據增加,而Mapeduce卻進行全局計算,完美地符合了他對數據處理的期望!
Hadoop也存在某個節點數據丟失的問題,但隨着流式計算,丟失的數據終究會隨着系統的正常而被最終合併,因此數據最終是一致的。
Hadoop不能進行實時計算咋辦?作者又構建了一套基於Cassandra和ElephantDB的實時數據處理系統。。。。搞的無比複雜!

3.4 質疑4:分區容錯概念有誤導

【5】的作者主要質疑【6】,但比較清晰得揭露了CAP的概念之間的模糊。
【5】認爲,可用性和一致性是分佈式系統的屬性,而分區卻是網絡的一個屬性。不能再問題發生時是否選擇要不要分區,而是應該在分區既定的情況下選擇要一致性還是可用性。網絡分區會發生在兩種情況:
  • 交換機失敗,導致網絡發生【6】中描述的情況,網絡被分成幾個子網
  • 機器延遲或死機,導致某些server失去聯繫
【6】中所謂的分區就是情況1,每個獨立的子網還能正常運作,作者認爲這種分區條件非常苛刻,更傾向於認爲這只是分區可用性的一種度量方式(發給每個子網的請求都有正確的response)。
而實際上,因爲機器原因發生的分區的情況更常見一些,如果“很多”機器都發生故障,系統會因爲一個“多數派”的丟失而導致不可用(比如,因爲多數不存在,最新的讀可能無法讀取到上一次的寫)。一句話:分區也同時蘊涵着不可用,這兩個概念之間存在重疊。
作者認爲,CAP比較合理的表達方式應該是:在一個允許網絡發生故障的系統中,該選擇一致性還是可用性?
當系統的機器數量持續增加時,一致性會加劇時延,維護一致性的成本會非常之高,因此我們基本就剩下一種選擇:在允許網絡失敗的系統中,更多地是選擇可用性。而Zookeeper、Hadoop之所以選擇一致性,是因爲這些系統多數是有在同一集羣的少數節點構成!
【5】的作者其實間接地否認了“3箇中同時滿足2個”這樣的誤解,而是從更深層次探討了CAP的本質,但並沒有試圖推翻CAP。

4.對質疑的迴應

面對大量的質疑,Brewer和Lynch終於坐不住了,因此兩人紛紛出來澄清:
Brewer於2012年重申【1】:
  • ”3箇中的2個“這個表述是不準確的,在某些分區極少發生的情況下,三者能順暢地在一起配合
  • CAP不僅僅是發生在整個系統中,可能是發生在某個子系統或系統的某個階段
該聲明並不否認像質疑3那種三個因素協同工作的情況,並把CAP應用在一些更細粒度的場景中。

Lynch也在10年後的2012年重寫了論文【3】,該論文主要做了幾件事:
  • 把CAP理論的證明侷限在原子讀寫的場景,並申明不支持數據庫事務之類的場景
  • 一致性場景不會引入用戶agent,只是發生在後臺集羣之內
  • 把分區容錯歸結爲一個對網絡環境的陳述,而非之前一個獨立條件。這實際上就是更加明確了概念
  • 引入了活性(liveness)和安全屬性(safety),在一個更抽象的概念下研究分佈式系統,並認爲CAP是活性與安全熟悉之間權衡的一個特例。其中的一致性屬於liveness,可用性屬於safety
  • 把CAP的研究推到一個更廣闊的空間:網絡存在同步、部分同步;一致性性的結果也從僅存在一個到存在N個(部分一致);引入了通信週期round,並引用了其他論文,給出了爲了保證N個一致性結果,至少需要通信的round數。也介紹了其他人的一些成果,這些成果分別都對CAP的某一個方面做出了特殊的貢獻!
其實Lynch的論文主要就是兩件事:縮小CAP適用的定義,消除質疑的場景;展示了CAP在非單一一致性結果下的廣闊的研究結果!並順便暗示CAP定理依舊正確!
從此論文還是可以看出,Lynch的功力高出其他質疑者好多!

5. 該如何看待CAP?

首先肯定的是,CAP並不適合再作爲一個適應任何場景的定理,它的正確性更加適合基於原子讀寫的NoSQL場景。質疑雖然很多,但很多質疑者只是偷歡概念,並沒有解決各個因素之間的取捨問題。而無論如何C、A、P這個三個概念始終存在任何分佈式系統,只是不同的模型會對其有不同的呈現,可能某些場景對三者之間的關係敏感,而另一些不敏感。在所有的質疑當中,質疑4是分析的比較中肯的,其清晰的概念分析該讓我們對CAP有更深入的理解!
就像Lynch所說,現在分佈式系統有很多特性,比如擴展性、優雅降級等,雖然時間的發展,或許這些也會被納入研究範疇,而作爲開發者,這都是我們需要考慮的問題,而不僅是CAP三者!

6.參考資料 

【1】http://en.wikipedia.org/wiki/Cap_theorem
【2】http://lpd.epfl.ch/sgilbert/pubs/BrewersConjecture-SigAct.pdf
【3】http://groups.csail.mit.edu/tds/papers/Gilbert/Brewer2.pdf
【4】http://markburgess.org/blog_cap.html
【5】http://blog.cloudera.com/blog/2010/04/cap-confusion-problems-with-partition-tolerance/
【6】http://cacm.acm.org/blogs/blog-cacm/83396-errors-in-database-systems-eventual-consistency-and-the-cap-theorem/fulltext
【7】http://nathanmarz.com/blog/how-to-beat-the-cap-theorem.html
【8】http://highscalability.com/blog/2011/11/23/paper-dont-settle-for-eventual-scalable-causal-consistency-f.html
發佈了113 篇原創文章 · 獲贊 69 · 訪問量 45萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章