正確理解CAP理論

mic_saber發表於2018-12-13

  

目錄

常見的理解及分析

更深入的探究:兩種重要的分散式場景

結論


目前,CAP(Consistency一致性、Availability可用性、Partition-tolerance分割槽可容忍性)理論普遍被當作是大資料技術的理論基礎。同時,根據該理論,業界有一種非常流行、非常“專業”的認識,那就是:關係型資料庫設計選擇了C(一致性)與A(可用性),NoSQL資料庫設計則不同。其中,HBase選擇了C(一致性)與P(分割槽可容忍性),Cassandra選擇了A(可用性)與P(分割槽可容忍性)。

  該說法現在似乎已經成為一種經典認知,無論是初學大資料技術,還是已經有了相當經驗的技術人員,都將其奉為真理。大家大概是認為,從CAP這樣著名的理論推匯出來的結論,當然是權威而又正確的,最起碼在形式上感覺是專業而又嚴肅的。有人甚至還將這種認知畫成一個三角形圖,三個頂點分別是C、A、P,三條邊分別是關係型資料庫、HBase與Cassandra,這樣一來,CAP理論就顯然更加神聖了。

  實際上,這種認識是不準確的,甚至是不正確的。暫且不說深入的分析與研究,只要先從表面上簡單分析一下,你就能發現問題:難道說從理論上講Cassandra就一定比HBase的可用性更高嗎?而要要徹底搞清楚這個問題,還得先從CAP理論本身開始研究。

常見的理解及分析

  目前流行的、對CAP理論解釋的情形是從同一資料在網路環境中的多個副本出發的。為了保證資料不會丟失,在企業級的資料管理方案中,一般必須考慮資料的冗餘儲存問題,而這應該是通過在網路上的其他獨立物理儲存節點上保留另一份、或多份資料副本來實現的(如附圖所示)。因為在同一個儲存節點上的資料冗餘明顯不能解決單點故障問題,這與通過多節點叢集來提供更好的計算可用性的道理是相同的。



附圖 CAP理論示意圖

  其實,不用做嚴格的證明也可以想見,如附圖的情況,資料在節點A、B、C上保留了三份,如果對節點A上的資料進行了修改,然後再讓客戶端通過網路對該資料進行讀取。那麼,客戶端的讀取操作什麼時候返回呢?

  有這樣兩種情況:一種情況是要求節點A、B、C的三份資料完全一致後返回。也就是說,這時從任何一個網路節點讀取的資料都是一樣的,這就是所謂的強一致性讀。很明顯,這時資料讀取的Latency要高一些(因為要等資料在網路中的複製),同時A、B、C三個節點中任何一個當機,都會導致資料不可用。也就是說,要保證強一致性,網路中的副本越多,資料的可用性就越差;

  另一種情況是,允許讀操作立即返回,容忍B節點的讀取與A節點的讀取不一致的情況發生。這樣一來,可用性顯然得到了提高,網路中的副本也可以多一些,唯一得不到保證的是資料一致性。當然,對寫操作同樣也有多個節點一致性的情況,在此不再贅述。

  可以看出,上述對CAP理論的解釋主要是從網路上多個節點之間的讀寫一致性出發考慮問題的。而這一點,對於關係型資料庫意味著什麼呢?當然主要是指通常所說的Standby(關於分散式事務,涉及到更多考慮,隨後討論)情況。對此,在實踐中我們大多已經採取了弱一致性的非同步延時同步方案,以提高可用性。這種情況並不存在關係型資料庫為保證C、A而放棄P的情況;而對海量資料管理的需求,關係型資料庫擴充套件過程中所遇到的效能瓶頸,似乎也並不是CAP理論中所描述的那種原因造成的。那麼,上述流行的說法中所描述的關係型資料庫為保證C、A而犧牲P到底是在指什麼呢?

  因此,如果根據現有的大多數資料對CAP理論的如上解釋,即只將其當作分散式系統中多個資料副本之間的讀寫一致性問題的通用理論對待,那麼就可以得出結論:CAP既適用於NoSQL資料庫,也適用於關係型資料庫。它是NoSQL資料庫、關係型資料庫,乃至一切分散式系統在設計資料多個副本之間讀寫一致性問題時需要遵循的共同原則。

更深入的探究:兩種重要的分散式場景

  在本文中我們要說的重點與核心是:關於對CAP理論中一致性C的理解,除了上述資料副本之間的讀寫一致性以外,分散式環境中還有兩種非常重要的場景,如果不對它們進行認識與討論,就永遠無法全面地理解CAP,當然也就無法根據CAP做出正確的解釋。但可惜的是,目前為止卻很少有人提及這兩種場景:那就是事務與關聯。

  先來看看分散式環境中的事務場景。我們知道,在關係型資料庫的事務操作遵循ACID原則,其中的一致性C,主要是指一個事務中相關聯的資料在事務操作結束後是一致的。所謂ACID原則,是指在寫入/異動資料的過程中,為保證交易正確可靠所必須具備的四個特性:即原子性(Atomicity,或稱不可分割性)、一致性(Consistency)、隔離性(Isolation,又稱獨立性)和永續性(Durability)。

  例如銀行的一個存款交易事務,將導致交易流水錶增加一條記錄。同時,必須導致賬戶表餘額發生變化,這兩個操作必須是一個事務中全部完成,保證相關資料的一致性。而前文解釋的CAP理論中的C是指對一個資料多個備份的讀寫一致性。表面上看,這兩者不是一回事,但實際上,卻是本質基本相同的事物:資料請求會等待多個相關資料操作全部完成才返回。對分散式系統來講,這就是我們通常所說的分散式事務問題。

  眾所周知,分散式事務一般採用兩階段提交策略來實現,這是一個非常耗時的複雜過程,會嚴重影響系統效率,在實踐中我們儘量避免使用它。在實踐過程中,如果我們為了擴充套件資料容量將資料分散式儲存,而事務的要求又完全不能降低。那麼,系統的可用性一定會大大降低,在現實中我們一般都採用對這些資料不分散儲存的策略。

  當然,我們也可以說,最常使用的關係型資料庫,因為這個原因,擴充套件性(分割槽可容忍性P)受到了限制,這是完全符合CAP理論的。但同時我們應該意識到,這對NoSQL資料庫也是一樣的。如果NoSQL資料庫也要求嚴格的分散式事務功能,情況並不會比關係型資料庫好多少。只是在NoSQL的設計中,我們往往會弱化甚至去除事務的功能,該問題才表現得不那麼明顯而已。

  因此,在擴充套件性問題上,如果要說關係型資料庫是為了保證C、A而犧牲P,在儘量避免分散式事務這一點上來看,應該是正確的。也就是說:關係型資料庫應該具有強大的事務功能,如果分割槽擴充套件,可用性就會降低;而NoSQL資料庫乾脆弱化甚至去除了事務功能,因此,分割槽的可擴充套件性就大大增加了。

  再來看看分散式環境中的關聯場景。初看起來,關係型資料庫中常用的多表關聯操作與CAP理論就更加不沾邊了。但仔細考慮,也可以用它來解釋資料庫分割槽擴充套件對關聯所帶來的影響。對一個資料庫來講,採用了分割槽擴充套件策略來擴充容量,資料分散儲存了,很顯然多表關聯的效能就會下降,因為我們必須在網路上進行大量的資料遷移操作,這與CAP理論中資料副本之間的同步操作本質上也是相同的。

  因此,如果要保證系統的高可用性,需要同時實現強大的多表關係操作的關係型資料庫在分割槽可擴充套件性上就遇到了極大的限制(即使是那些採用了各種優秀解決方案的MPP架構的關係型資料庫,如TeraData,Netezza等,其水平可擴充套件性也是遠遠不如NoSQL資料庫的),而NoSQL資料庫則乾脆在設計上弱化甚至去除了多表關聯操作。那麼,從這一點上來理解“NoSQL資料庫是為了保證A與P,而犧牲C”的說法,也是可以講得通的。當然,我們應該理解,關聯問題在很多情況下不是並行處理的優點所在,這在很大程度上與Amdahl定律相符合。

  所以,從事務與關聯的角度來關係型資料庫的分割槽可擴充套件性為什麼受限的原因是最為清楚的。而NoSQL資料庫也正是因為弱化,甚至去除了像事務與關聯(全面地講,其實還有索引等特性)等在分散式環境中會嚴重影響系統可用性的功能,才獲得了更好的水平可擴充套件性。

  那麼,如果將事務與關聯也納入CAP理論中一致性C的範疇的話,問題就很清楚了:關於“關係型資料庫為了保證一致性C與可用性A,而不得不犧牲分割槽可容忍性P”的說法便是正確的了。但關於“NoSQL選擇了C與P,或者A與P”的說法則是錯誤的,所有的NoSQL資料庫在設計策略的大方向上都是選擇了A與P(雖然對同一資料多個副本的讀寫一致性問題的設計各有不同),從來沒有完全選擇C與P的情況存在。

結論

  現在看來,如果理解CAP理論只是指多個資料副本之間讀寫一致性的問題,那麼它對關係型資料庫與NoSQL資料庫來講是完全一樣的,它只是執行在分散式環境中的資料管理設施在設計讀寫一致性問題時需要遵循的一個原則而已,卻並不是NoSQL資料庫具有優秀的水平可擴充套件性的真正原因。而如果將CAP理論中的一致性C理解為讀寫一致性、事務與關聯操作的綜合,則可以認為關係型資料庫選擇了C與A,而NoSQL資料庫則全都是選擇了A與P,但並沒有選擇C與P的情況存在。這才是用CAP理論來支援NoSQL資料庫設計正確認識。

  其實,這種認識正好與被廣泛認同的NoSQL的另一個理論基礎相吻合,即與ACID對著幹的BASE(基本可用性、軟狀態與最終一致性)。因為BASE的含義正好是指“NoSQL資料庫設計可以通過犧牲一定的資料一致性和容錯性來換取高效能的保持甚至提高”,即NoSQL資料庫都應該是犧牲C來換取P,而不是犧牲A。可用性A正好是所有NoSQL資料庫都普遍追求的特性。

相關文章