本文轉載自 分佈式理論:CAP三選二html
CAP是什麼?node
CAP理論,被戲稱爲[帽子理論]。CAP理論由Eric Brewer在ACM研討會上提出,然後CAP被奉爲分佈式領域的重要理論[1] 。mysql
分佈式系統的CAP理論:首先把分佈式系統中的三個特性進行了以下概括:git
● 一致性(C):在分佈式系統中的全部數據備份,在同一時刻是否一樣的值。(等同於全部節點訪問同一份最新的數據副本)github
● 可用性(A):在集羣中一部分節點故障後,集羣總體是否還能響應客戶端的讀寫請求。(對數據更新具有高可用性)算法
● 分區容忍性(P):以實際效果而言,分區至關於對通訊的時限要求。系統若是不能在時限內達成數據一致性,就意味着發生了分區的狀況,必須就當前操做在C和A之間作出選擇。(分區狀態能夠理解爲部分機器不連通了,好比機器掛了,繁忙失去響應,單機房故障等)sql
Partition字面意思是網絡分區,即因網絡因素將系統分隔爲多個單獨的部分,有人可能會說,網絡分區的狀況發生機率很是小啊,是否是不用考慮P,保證CA就好。要理解P,咱們看回CAP證實中P的定義: In order to model partition tolerance, the network will be allowed to losearbitrarily many messages sent from one node to another.數據庫
網絡分區的狀況符合該定義,網絡丟包的狀況也符合以上定義,另外節點宕機,其餘節點發往宕機節點的包也將丟失,這種狀況一樣符合定義。現實狀況下咱們面對的是一個不可靠的網絡、有必定機率宕機的設備,這兩個因素都會致使Partition,於是分佈式系統實現中 P 是一個必須項,而不是可選項。緩存
高可用、數據一致性是不少系統設計的目標,可是分區又是不可避免的事情。咱們來看一看分別擁有CA、CP和AP的狀況。bash
CA without P:若是不要求P(不容許分區),則C(強一致性)和A(可用性)是能夠保證的。但其實分區不是你想不想的問題,而是始終會存在,CA系統基本上是單機系統,好比單機數據庫。2PC是實現強一致性的具體手段。
from http://www.cs.berkeley.edu/~brewer/cs262b-2004/PODC-keynote.pdf
CP without A:若是不要求A(可用),至關於每一個請求都須要在Server之間強一致,而P(分區)會致使同步時間無限延長,如此CP也是能夠保證的。不少傳統的數據庫分佈式事務都屬於這種模式。
from 同上
AP wihtout C:要高可用並容許分區,則需放棄一致性。一旦分區發生,節點之間可能會失去聯繫,爲了高可用,每一個節點只能用本地數據提供服務,而這樣會致使全局數據的不一致性。如今衆多的NoSQL都屬於此類。
from 同上
CAP理論的證實
該理論由brewer提出,2年後就是2002年,Lynch與其餘人證實了Brewer猜測,從而把CAP上升爲一個定理。可是,它只是證實了CAP三者不可能同時知足,並無證實任意兩者均可知足的問題,因此,該證實被認爲是一個收窄的結果。
Lynch的證實相對比較簡單:採用反證法,若是三者可同時知足,則由於容許P的存在,必定存在Server之間的丟包,如此則不能保證C,證實簡潔而嚴謹。
在該證實中,對CAP的定義進行了更明確的聲明:
· C:一致性被稱爲原子對象,任何的讀寫都應該看起來是「原子「的,或串行的。寫後面的讀必定能讀到前面寫的內容。全部的讀寫請求都好像被全局排序同樣。
· A:對任何非失敗節點都應該在有限時間內給出請求的迴應。(請求的可終止性)
· P:容許節點之間丟失任意多的消息,當網絡分區發生時,節點之間的消息可能會徹底丟失。
對於CAP進一步的案例解釋
2010年的這篇文章brewers-cap-theorem-on-distributed-systems/,用了三個例子來闡述CAP,分別是example1:單點的mysql;example2:兩個mysql,但不一樣的mysql存儲不一樣的數據子集,至關於sharding;example3:兩個mysql,對A的一個insert操做,須要在B上執行成功才認爲操做完成(相似複製集)。做者認爲在example1和example2上 都能保證強一致性,但不能保證可用性;在example3這個例子,因爲分區(partition)的存在,就須要在一致性與可用性之間權衡。對於複製而言,在不少場景下不追求強一致性。好比用戶支付以後,交易記錄落地了;但可能消費記錄的消息同步存在延遲,好比消息阻塞了。在金融業務中,採起相似兩地三中心架構,每每可能採起本地數據和異地機房數據同時寫成功再返回的方式。這樣付出了性能的損耗,響應時間變長。但發生機房故障後,能確保數據是徹底能夠讀寫的,保障了一致性。
CAP理論澄清
[CAP理論十二年回顧:」規則」變了]一文首發於 Computer 雜誌,後由InfoQ和IEEE聯合呈現,很是精彩[2],文章表達了幾個觀點。
「三選二」是一個僞命題
不是爲了P(分區容忍性),要在A和C之間選擇一個。分區不多出現,CAP在大多數時候容許完美的C和A。但當分區存在或可感知其影響的狀況下,就要預備一種策略去探知分區並顯式處理其影響。這樣的策略應分爲三個步驟:探知分區發生,進入顯式的分區模式以限制某些操做,啓動恢復過程以恢復數據一致性並補償分區期間發生的錯誤。
「一致性的做用範圍」其實反映了這樣一種觀念,即在必定的邊界內狀態是一致的,但超出了邊界就無從談起。好比在一個主分區內能夠保證完備的一致性和可用性,而在分區外服務是不可用的。Paxos算法和原子性多播(atomic multicast)系統通常符合這樣的場景。像Google的通常作法是將主分區歸屬在單個數據中內心面,而後交給Paxos算法去解決跨區域的問題,一方面保證全局協商一致(global consensus)如Chubby,一方面實現高可用的持久性存儲如Megastore。
ACID、BASE、CAP
ACID和BASE 這兩個術語都好記有餘而精確不足,出現較晚的BASE硬湊的感受更明顯,它是「Basically Available, Softstate, Eventually consistent(基本可用、軟狀態、最終一致性)」的首字母縮寫。其中的軟狀態和最終一致性這兩種技巧擅於對付存在分區的場合,並所以提升了可用性。
CAP與ACID的關係更復雜一些,也所以引發更多誤解。其中一個緣由是ACID的C和A字母所表明的概念不一樣於CAP的C和A。還有一個緣由是選擇可用性只部分地影響ACID約束。
進一步看[分區]以後
用一下這張圖[引用自 link 2],在狀態S的時候是非分區狀態,而分區模式則演化出來了S1,S2,那麼問題來了,分區恢復以後,狀態到底是多少呢?有幾種解決方案。
分區恢復策略:可交換多副本數據類型
注意,能支持此類處理的場景是有限的。
riak_dt 就是這樣一種保障最終一致性實現的數據結構,它分爲Operation-based CRDTs、State-based CRDTs 2種形態。
riak_dt link參見 link [3]。
State-based CRDTs
State-based CRDTs are called convergent replicated data types,or CvRDTs. In contrast to CmRDTs, CvRDTs send their full localstate to other replicas. CvRDTs have the following local interface:
· query – reads the state of the replica, with no sideeffects
· update – writes to the replica state in accordance withcertain restrictions
· merge – merges local state with the state of some remotereplica
The merge function must be commutative, associative, andidempotent. It provides a join for any pair of replica states, so theset of all states forms asemilattice. The update functionmust monotonically increase the internal state, according to thesame partial order rules as the semilattice.
from:https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type
分區恢復策略:回放合併
在分區恢復過程當中,設計師必須解決兩個問題:
分區兩側的狀態最終必須保持一致, 而且必須補償分區期間產生的錯誤。 如上圖所示,對於分區恢復的狀態S*能夠經過未分區時的狀態S爲起點,而後按順序[回放]相應的變化事件[以特定方式推動分區兩側的一系列操做,並在過程當中一直保持一致的狀態。]。Bayou[link 4]就是這個實現機制,它會回滾數據庫到正確的時刻並按無歧義的、肯定性的順序從新執行全部的操做,最終使全部的節點達到相同的狀態。
對於有衝突的狀況,好比版本管理軟件cvs,存在人工介入、消除衝突的處理策略。
有限制處理
有限制處理:[link 2]提的自動櫃員機補償問題,比較形象說明了這個問題。此問題本質上是可用性和一致性的折衷處理。
以自動櫃員機(ATM)的設計來講,強一致性看似符合邏輯的選擇,但現實狀況是可用性遠比一致性重要。理由很簡單:高可用性意味着高收入。無論怎麼樣,討論如何補償分區期間被破壞的不變性約束,ATM的設計很適合做爲例子。
ATM的基本操做是存款、取款、查看餘額。關鍵的不變性約束是餘額應大於或等於零。由於只有取款操做會觸犯這項不變性約束,也就只有取款操做將受到特別對待,其餘兩種操做隨時均可以執行。
ATM系統設計師能夠選擇在分區期間禁止取款操做,由於在那段時間裏沒辦法知道真實的餘額,固然這樣會損害可用性。現代ATM的作法正相反,在stand-in模式下(即分區模式),ATM限制淨取款額不得高於k,好比k爲$200。低於限額的時候,取款徹底正常;當超過限額的時候,系統拒絕取款操做。這樣,ATM成功將可用性限制在一個合理的水平上,既容許取款操做,又限制了風險。
分區結束的時候,必須有一些措施來恢復一致性和補償分區期間系統所形成的錯誤。狀態的恢復比較簡單,由於操做都是符合交換率的,補償就要分幾種狀況去考慮。最後的餘額低於零違反了不變性約束。因爲ATM已經把錢吐出去了,錯誤成了外部實在。銀行的補償辦法是收取透支費並期望顧客償還。由於風險已經受到限制,問題並不嚴重。還有一種狀況是分區期間的某一刻餘額已經小於零(但ATM不知道),此時一筆存款從新將餘額變爲正的。銀行能夠追溯產生透支費,也能夠由於顧客已經繳付而忽略該違反狀況。
總而言之,由於通訊延遲的存在,銀行系統不依靠一致性來保證正確性,而更多地依靠審計和補償。「空頭支票詐騙」也是相似的例子,顧客趕在多家分行對帳以前分別取出錢來而後逃跑。透支的錯誤事後纔會被發現,對錯誤的補償也許體現爲法律行動的形式。
此前,中行IBM大型機宕機,系統沒有第一時間切換到熱備或者異地容災上,直接影響中行的信用卡支付相關業務,直到4小時以後才恢復服務。有對應的的緣由包括平常演練等問題,等更重要的是在[可用性和一致性]之間選擇了一致性,4H以後提供服務,備庫仍然主要起數據備份的做用。
有限制處理方案是須要冒險滴,爲了保障可用性,沒法保障數據100%精確,能夠折衷提供部分有損服務。好比取款根據信用是否是能限制必定金額,而存款是Ok的等等。大額對公業務也能夠採起具體辦法,固然這將在精細化管理服務能力及配套能力上付出更多的IT成本。
有關中行IBM大型機宕機的報道link:
http://digi.tech.qq.com/zt2013/syibm/
http://www.infoq.com/cn/news/2013/04/BOC-Downtime/
超越CAP?
Nathan Marz:How to beat theCAP theorem
2011年11月Twitter的首席工程師Nathan Marz寫了一篇文章,描述了他是如何試圖戰勝CAP定理的: How to beat the CAP theorem
做者表示不是要「擊敗」CAP,而是嘗試對數據存儲系統進行從新設計,以可控的複雜度來實現CAP。Marz認爲一個分佈式系統面臨CAP難題的兩大問題就是:在數據庫中如何使用不斷變化的數據,如何使用算法來更新數據庫中的數據。
Marz提出了2個基本思路:
數據不存在update,只存在append操做。這樣就把對數據的處理由CRUD變爲CR;一樣的,delete操做也能夠處理爲add一條新記錄:好比 友強取消了對山丘的關注,傳統關係型數據庫是在關係表刪除一條記錄,而Marz也能夠新增一條關係爲[取消]的記錄。
全部的數據的操做就只剩下Create和Read。把Read做爲一個Query來處理,而一個Query就是一個對整個數據集執行一個函數操做。
總結,在有必定時序性,且對實時一致性要求不高的場景下能夠選擇使用,畢竟在問題解決域多了一把錘子。Query過程當中的跨分區函數仍然是一種合併的變種(Merge)!
OceanBase的另類之路
既然更新數據涉及到分區問題,那麼能不能把更新放到一個服務器呢[腦洞大開]?而後經過強大的軟件+硬件能力一塊兒去保障它!同時已經不修改的數據自然具有可擴展性!這是我粗暴理解OceanBase的基本設計思想。
link[5] 寫道:做爲電子商務企業,淘寶和其餘公司的業務對一致性和可用性的要求高於分區容錯性,數據特徵是數據總量龐大且逐步增長,單位時間內的數據更新量並不大,但實時性要求很高。這就要求咱們提供一套更加偏重於支持CA特性的系統,同時兼顧可分區性,而且在實時性、成本、性能等方面表現良好。
OceanBase的邏輯架構簡圖
關於UpdateServer的性能問題
其實大部分數據庫天天的修改次數至關有限,只有少數修改比較頻繁的數據庫纔有天天幾億次的修改次數。另外,數據庫平均每次修改涉及的數據量不多,不少時候只有幾十個字節到幾百個字節。假設數據庫天天更新1億次,平均每次須要消耗100字節,天天插入1000萬次,平均每次須要消耗1000字節,那麼,一天的修改量爲:1億 * 100 + 1000萬 *1000 = 20GB,若是內存數據結構膨脹2倍,佔用內存只有40GB。而當前主流的服務器均可以配置96GB內存,一些高檔的服務器甚至能夠配置192GB、384GB乃至更多內存。
TiDB
TiDB 是國內 PingCAP 團隊開發的一個分佈式 SQL 數據庫。其靈感來自於 Google 的 F1, TiDB 支持包括傳統 RDBMS 和 NoSQL 的特性。從下面這篇訪談來看,分佈式事務早期版本中,他們參考的是Google 的 Percolator 的模型。目前該項目逐步歸入商用,有興趣的朋友參考下面的link[6]。
[1] link:http://www.cs.berkeley.edu/~brewer/cs262b-2004/PODC-keynote.pdf
[2] link:http://www.infoq.com/cn/articles/cap-twelve-years-later-how-the-rules-have-changed/
[3] link:https://github.com/basho/riak_dt
[4] link:http://www.cs.berkeley.edu/~brewer/cs262b/update-conflicts.pdf
[5] link:http://code.taobao.org/p/OceanBase/wiki/intro/
[6] link:http://mt.sohu.com/20160122/n435472384.shtml
總結:CAP是分佈式領域的重要理論,但不表明徹底不能有延展的解讀和思考。另外[三選二]自己也是有條件成立的,不能簡單誤讀,一切取決於應用場景。若是不加選擇按照理論形式無異於刻舟求劍。
欲瞭解更多有關分佈式緩存方面的內容,請閱讀《深刻分佈式緩存:從原理到實踐》一書。