拜託!這才是分散式系統CAP的正確開啟方式!

拜託!這才是分散式系統CAP的正確開啟方式!

作者 | bdseeker

責編 | 鄭麗媛

拜託!這才是分散式系統CAP的正確開啟方式!

前言

糾結了很久要不要寫這一篇,作為分散式系統的核心理論簡單說說容易,聊透卻很難,轉念一想,如果不寫這篇,算什麼想通透大資料呢!並且這本身就違背了我寫作的初衷;加之正好前幾天和同事以ZooKeeper的使用者行為反推了CAP理論,回過頭來細琢磨了下,還蠻有意思的!閒話少絮,我們進入正題!

本文宗旨:深入淺出!聊透!

拜託!這才是分散式系統CAP的正確開啟方式!

“紙面”上的CAP

相信很多同學都聽過CAP這個理論,為了避免我們認知不同,我們先來統一下知識起點。

CAP理論在1999年一經提出就成為了分散式系統領域的頂級教義。並表明分散式服務中,存在三要素:一致性、可用性、分割槽容錯性。而“CAP”就是Consistency/Availability/Partition Tolerance三個單詞縮寫。

一致性:分散式系統中,一份資料一般會存在多個副本,要求多副本資料對於資料的更新與單份資料相同,即強一致性。

可用性:在任意的時刻,對分散式系統來說要保證在限定延時內正常響應客戶端的讀寫請求,並且不會報錯。(提前糾正一個誤區,這裡的可用性並不是咱們通常理解的服務的SLA可用性,即3個9、4個9之類的定義。實際上指的是是資料訪問的可達性。)

分割槽容錯性:在分散式服務中,節點之間網路通訊異常導致(丟包、延遲、中斷等)的網路分割槽現象是必然存在的,要保證出現網路分割槽現象時,分散式系統不受影響。

原論述表明CAP是不可以兼得的,一個系統需要放寬一點才能滿足其他兩點,因此此時對於分散式系統來說其實就三個選項CP、AP、CA三種,但是不能同時滿足CAP。但是由於網路問題是不可避免的現象,所以預想的分散式系統都會往AP和CP上去權衡靠攏。如下所示:

拜託!這才是分散式系統CAP的正確開啟方式!

CAP模型

嘗試沙盤推演分散式系統的CA、AP、CP選型

1。 先說說CA選型

實際上CA選型對於我們來說並不陌生,Oracle和MySQL資料庫就是最好的例子,他們擁有強一致性和可用性,雖然Oracle RAC看似是分散式,但是依然選擇節點本身的共享儲存或者邏輯ASM儲存;MySQL主從實際上可以理解成多個單點MySQL,透過Binlog資料同步逐漸將資料同步到所有單點上,寫主讀從,因此依舊是是單點的CA系統,捨棄了P。我們暫時不討論資料庫事務。這裡我們主要還是聊聊正兒八經的分散式系統。

2。 為什麼CP系統不能滿足A?

CP系統意味著是資料是單副本,分佈在多個節點上,如下圖所示,D1-Dn代表著分散式系統的多個節點,當不同的Client訪問節點上的資料時,由於不涉及副本資料的同步,每個節點都是最新的資料,資料必然是強一致性的。此時是滿足C、P要素。但是此時如果發生網路分割槽問題,那麼資料就必然丟失不可訪問了,此時可用性A受到了影響。

拜託!這才是分散式系統CAP的正確開啟方式!

3。 為什麼AP系統不能滿足C?

AP系統意味著資料是有多副本的,即使出現網路分割槽問題,也不會丟失資料導致不可用,但是會存在資料一致性問題。如下圖所示,資料D1有3個副本,D1-1、D1-2、D1-3,並且分佈在不同節點上。在T1時刻,正常情況下每個客戶端讀到的資料都是X=1,在T2時刻,Client1嘗試將資料更新為X=2,接下來T3時刻請求到達分散式系統後端,將D1-1副本資料更新成功,但是在T4時刻資料副本D1-1和D1-2副本之間出現網路分割槽問題,D1-2並未被置成X=2,此時Client2和Client3讀一份資料就出現了不同的返回值,雖然資料可達,但是由此帶來了資料一致性問題。

拜託!這才是分散式系統CAP的正確開啟方式!

AP選型

如果看到這裡並且理解了,那麼恭喜你,證明你對分散式確實有一定的理解了。我們再接再厲,繼續往下看,相信你對CAP的理解會上一個層次。

拜託!這才是分散式系統CAP的正確開啟方式!

在CAP中“迷失”

在上一節中我們解析了“紙面”上的CAP,按照其推論,分散式系統的世界看似很完美,絕大多數架構師也將CAP奉為第一原則,在設計系統之初就選擇傾向於CP或者AP。即為了保證強一致性犧牲可用性或者為了可用性而降低一致性。

可是仔細一想,上一節所講述的分散式世界真的這麼完美嗎?細細想來,誤區太多了!

誤區一 “三選二”的先入為主

儘管網路問題在我們日常運營分散式系統中經常發生,但是相比正常時間,網路分割槽依然是小機率事件,因此並不應該在設計之處就放棄C或者A,在正常情況下分散式系統一定是要同時兼顧CAP。

誤區二 CAP的定義極端

在上面的CAP理論中,分散式系統在網路分割槽的既定現實下一定會保證P,而在A、C中選取其一,但事實上A、C的選擇並不是非黑即白的。因此上面的CAP理論過於粗曠籠統。

設計具體分散式服務時,實際上需要區分多個子模組,如計算模組/排程模組/儲存模組等,在遭遇網路分割槽時,會實行將部分子模組降級等策略,從而細粒度取捨A和C,而不是直接影響整個服務、所有資料。

誤區三 CAP的標準模糊

CAP理論中只為C、A、P定義概念,但是卻不定義標準,C、A、P3個要素都是定義在時間這個維度的基礎上,一切都是基於時間檢視,多長時間的資料算不違反一致性呢?多久的訪問時間算影響資料訪問的可用性呢?或者再較真一點,多久時間的網路問題算作網路分割槽呢?一切的本質都是時間。因此在理論基礎上需要將CAP定性細分。

針對網路分割槽可以按照一定通訊週期,分斂成單機網路分割槽、機器組網路分割槽(比如HDFS的機架感知實際上就是針對的就是後者);

針對一致性可以分成若干種一致性程度(後面的文章會講到);

針對資料訪問效率來說,按照P95/P99讀寫進行資料訪問效能的進行區分也不失為一種手段。

誤區四 CAP理論是否要帶Client玩?

CAP理論中並沒有明確系統邊界範圍,一個分散式系統不包括Client那算什麼分散式系統的呢?這裡我們就來嘮嘮CAP理論為什麼不包括Client。因為如果算上client的話,分散式叢集將更為複雜。

假設網路分割槽發生在Cient和分散式服務中間,那麼A肯定就無法達到了。

分散式服務一致性的效果就不是這麼明顯了,因為讀請求都到不了分散式系統。

如果Client和分散式服務中間發生網路分割槽,此時分散式服務無論再怎麼努力其實都是無用的。

雖然不帶著Client玩,但並不意味著Client不需要重視,個人認為分散式系統的Client中一定要儘量保證CA,而不必去考慮P。

拜託!這才是分散式系統CAP的正確開啟方式!

CAP的正確開啟方式

上面提到了,由於傳統CAP理論的存在一些誤區點,其將很多同學帶入錯誤的方向上,這裡開始我們聊一聊CAP的正確開啟方式。

CAP的目標狀

拜託!這才是分散式系統CAP的正確開啟方式!

如上圖所示:在未發生網路分割槽的T1時刻,這時的分散式系統是同時滿足CAP三要素的,各份資料一致性狀態是S,當到了T2時刻,發生了網路分割槽情況,此時各個節點,會記錄各個節點的狀態S1、S2,當T3時刻網路分割槽恢復時,需要將S1、S2狀態進行相應處理,這裡的部分實際上是很多分散式服務的重點:比如可以透過log end offset(Kafka)或者transaction id(Zookeeper)在分割槽發生後進行leader比對選舉,然後再進行資料同步。

精細化CAP理論

CAP為我們打開了一扇大門,但是過於寬泛無法適合所有場景,比如不適合資料庫事務,而強一致性C也會使得服務應用場景受限,因此理論需要細分領域,根據不同場景進行分類。

1。ACID原則

原子性(Atomicity)在事務中一個事務要麼成功,要麼失敗。不允許一個事務成功一半失敗一半。原子性就像我中午午休經常會去超市買水果,要麼就買選蘋果+結完賬才算購買成功;蘋果沒選好或者選好了沒結賬 都不算購買成功。

一致性(Consistency)在事務的開始和結束時,需要滿足一致性約束條件。什麼是一致性約束,咱們依舊拿去超市買蘋果舉例,超市只剩下20個蘋果了,我買了一個,對應的超市就應該減去一個蘋果。另外注意ACID中的一致性,是邏輯的一致性,而不是CAP中資料的一致性。

獨立性(Isolation)如果有多個事務同時發生,互相之間不能被影響,並且不知道對方的存在。咱們還去買蘋果,我挑了蘋果去結賬,有個大媽也挑了蘋果也去結賬。這時我們之間是互不影響的,相互獨立的。我沒帶錢買蘋果失敗也不影響大媽買蘋果成功。當然如果結完賬大媽看小夥子我長得帥,硬給我塞幾個蘋果,我也沒辦法

永續性(Durability)當事務執行成功的時候,對整個系統來說,這個更新就是永久的。我們依舊去去買蘋果,買完蘋果結賬之後,如果蘋果是好的,我想退款,超市是不會給我退的,對於超市來說這個賬單永久的,除非我買到了壞蘋果並且退款成功。

以上就是資料庫系統裡的ACID原則,主要針對資料庫事務,分散式事務我們後續的文章會講到。

2。BASE原則(這裡就不用買蘋果舉例了,因為找不到同一個蘋果的多個副本。 )

基本可用(Basically Available)系統大多數時間是可用的,允許偶爾的失敗。相比CAP的可用性來說,BASE中的基本可用,是允許分散式服務在請求響應時間上有損失的,原來10ms返回,現在100ms也不算做異常。

軟狀態(Soft State)允許分散式系統中的資料存在一箇中間狀態,這就意味允許系統在多個不同節點的資料副本存在資料延時。比如Kafka 的partition多個replica之間並不是一直同步的。相比CAP強一致性這種硬狀態來說,BASE中的S是允許同一資料的多副本之間存在延時的軟狀態。

最終一致性(Eventual Consistency)上面說到允許分散式系統存在中間的軟狀態,但是總得有個時間期限。否則就沒法玩兒了。在這個時間週期過後,必須保證所有副本保持資料一致性。從而達到資料的最終一致性。

3。CAP和BASE、ACID的關係

拜託!這才是分散式系統CAP的正確開啟方式!

AP、BASE和ACID的關係

如上圖所示,BASE和ACID實際上是CAP在不同選型的細分理論,CA的選型對應ACID原則,主要針對資料庫系統Oracle、MySQL等,AP選型對應BASE原則,比如Cassandra、Zookeeper、HDFS,而CP選型很遺憾目前還沒有一個原則能對應上。但是不妨礙咱們造一個,比如“BACP”,即基本可用、強一致性、分割槽容錯性,其對應的系統如HBase、Redis。

雖然CAP想在任意時刻都滿足比較難,但是還是不妨礙有巔峰產品問世,比如谷歌的Spanner雖然是CP系統,但是由於可用性非常之高,讓使用者一直以為他是CAP的產品,其依賴谷歌自建廣域網,讓我瞭解到基建的發達也是解決分散式系統網路分割槽問題的另一個方向;Tidb作為國內的開源代表,也是CP系統,雖然他距離Spanner還有差距,但是他公司的名字PingCAP讓我覺得,趕超只是時間問題。此外還有OceanBase也非常不錯,這塊瞭解的較少,以後有機會了解下。

至此CAP就解析完了,如果你能看到這裡,我必須手動點贊!祝咱們在大資料的路上越走越遠!相信堅持總會有所收穫!!!

拜託!這才是分散式系統CAP的正確開啟方式!