想成爲架構師,你必須掌握的CAP細節

理論的優點在於清晰簡潔、易於理解,但缺點就是高度抽象化,省略了很多細節,導致在將理論應用到實踐時,由於各種複雜情況,可能出現誤解和偏差,CAP 理論也不例外。如果我們沒有意識到這些關鍵的細節點,那麼在實踐中應用 CAP 理論時,就可能發現方案很難落地。

而且當談到數據一致性時,CAP、ACID、BASE 難免會被我們拿出來討論,原因在於這三者都是和數據一致性相關的理論,如果不仔細理解三者之間的差別,則可能會陷入一頭霧水的狀態,不知道應該用哪個纔好。

今天,我來講講CAP 的具體細節,簡單對比一下 ACID、BASE 幾個概念的關鍵區別點。

CAP 關鍵細節點

埃裏克·布魯爾(Eric Brewer)在《CAP 理論十二年回顧:“規則”變了》(http://www.infoq.com/cn/articles/cap-twelve-years-later-how-the-rules-have-changed)一文中詳細地闡述了理解和應用 CAP 的一些細節點,可能是由於作者寫作風格的原因,對於一些非常關鍵的細節點一句話就帶過了,這裏我特別提煉出來重點闡述。

  • CAP 關注的粒度是數據,而不是整個系統。

原文就只有一句話:

C 與 A 之間的取捨可以在同一系統內以非常細小的粒度反覆發生,而每一次的決策可能因爲具體的操作,乃至因爲牽涉到特定的數據或用戶而有所不同。

但這句話是理解和應用 CAP 理論非常關鍵的一點。CAP 理論的定義和解釋中,用的都是 system、node 這類系統級的概念,這就給很多人造成了很大的誤導,認爲我們在進行架構設計時,整個系統要麼選擇 CP,要麼選擇 AP。但在實際設計過程中,每個系統不可能只處理一種數據,而是包含多種類型的數據,有的數據必須選擇 CP,有的數據必須選擇 AP。而如果我們做設計時,從整個系統的角度去選擇 CP 還是 AP,就會發現顧此失彼,無論怎麼做都是有問題的。

以一個最簡單的用戶管理系統爲例,用戶管理系統包含用戶賬號數據(用戶 ID、密碼)、用戶信息數據(暱稱、興趣、愛好、性別、自我介紹等)。通常情況下,用戶賬號數據會選擇 CP,而用戶信息數據會選擇 AP,如果限定整個系統爲 CP,則不符合用戶信息數據的應用場景;如果限定整個系統爲 AP,則又不符合用戶賬號數據的應用場景。

所以在 CAP 理論落地實踐時,我們需要將系統內的數據按照不同的應用場景和要求進行分類,每類數據選擇不同的策略(CP 還是 AP),而不是直接限定整個系統所有數據都是同一策略。

  • CAP 是忽略網絡延遲的。

這是一個非常隱含的假設,布魯爾在定義一致性時,並沒有將延遲考慮進去。也就是說,當事務提交時,數據能夠瞬間複製到所有節點。但實際情況下,從節點 A 複製數據到節點 B,總是需要花費一定時間的。如果是相同機房,耗費時間可能是幾毫秒;如果是跨地域的機房,例如北京機房同步到廣州機房,耗費的時間就可能是幾十毫秒。這就意味着,CAP 理論中的 C 在實踐中是不可能完美實現的,在數據複製的過程中,節點 A 和節點 B 的數據並不一致。

不要小看了這幾毫秒或者幾十毫秒的不一致,對於某些嚴苛的業務場景,例如和金錢相關的用戶餘額,或者和搶購相關的商品庫存,技術上是無法做到分佈式場景下完美的一致性的。而業務上必須要求一致性,因此單個用戶的餘額、單個商品的庫存,理論上要求選擇 CP 而實際上 CP 都做不到,只能選擇 CA。也就是說,只能單點寫入,其他節點做備份,無法做到分佈式情況下多點寫入。

需要注意的是,這並不意味着這類系統無法應用分佈式架構,只是說“單個用戶餘額、單個商品庫存”無法做分佈式,但系統整體還是可以應用分佈式架構的。例如,下面的架構圖是常見的將用戶分區的分佈式架構。



我們可以將用戶 id 爲 0 ~ 100 的數據存儲在 Node 1,將用戶 id 爲 101 ~ 200 的數據存儲在 Node 2,Client 根據用戶 id 來決定訪問哪個 Node。對於單個用戶來說,讀寫操作都只能在某個節點上進行;對所有用戶來說,有一部分用戶的讀寫操作在 Node 1 上,有一部分用戶的讀寫操作在 Node 2 上。

這樣的設計有一個很明顯的問題就是某個節點故障時,這個節點上的用戶就無法進行讀寫操作了,但站在整體上來看,這種設計可以降低節點故障時受影響的用戶的數量和範圍,畢竟隻影響 20% 的用戶肯定要比影響所有用戶要好。這也是爲什麼挖掘機挖斷光纜後,支付寶只有一部分用戶會出現業務異常,而不是所有用戶業務異常的原因。

  • 正常運行情況下,不存在 CP 和 AP 的選擇,可以同時滿足 CA。

CAP 理論告訴我們分佈式系統只能選擇 CP 或者 AP,但其實這裏的前提是系統發生了“分區”現象。如果系統沒有發生分區現象,也就是說 P 不存在的時候(節點間的網絡連接一切正常),我們沒有必要放棄 C 或者 A,應該 C 和 A 都可以保證,這就要求架構設計的時候既要考慮分區發生時選擇 CP 還是 AP,也要考慮分區沒有發生時如何保證 CA

同樣以用戶管理系統爲例,即使是實現 CA,不同的數據實現方式也可能不一樣:用戶賬號數據可以採用“消息隊列”的方式來實現 CA,因爲消息隊列可以比較好地控制實時性,但實現起來就複雜一些;而用戶信息數據可以採用“數據庫同步”的方式來實現 CA,因爲數據庫的方式雖然在某些場景下可能延遲較高,但使用起來簡單。

  • 放棄並不等於什麼都不做,需要爲分區恢復後做準備。

CAP 理論告訴我們三者只能取兩個,需要“犧牲”(sacrificed)另外一個,這裏的“犧牲”是有一定誤導作用的,因爲“犧牲”讓很多人理解成什麼都不做。實際上,CAP 理論的“犧牲”只是說在分區過程中我們無法保證 C 或者 A,但並不意味着什麼都不做。因爲在系統整個運行週期中,大部分時間都是正常的,發生分區現象的時間並不長。例如,99.99% 可用性(俗稱 4 個 9)的系統,一年運行下來,不可用的時間只有 50 分鐘;99.999%(俗稱 5 個 9)可用性的系統,一年運行下來,不可用的時間只有 5 分鐘。分區期間放棄 C 或者 A,並不意味着永遠放棄 C 和 A,我們可以在分區期間進行一些操作,從而讓分區故障解決後,系統能夠重新達到 CA 的狀態。

最典型的就是在分區期間記錄一些日誌,當分區故障解決後,系統根據日誌進行數據恢復,使得重新達到 CA 狀態。同樣以用戶管理系統爲例,對於用戶賬號數據,假設我們選擇了 CP,則分區發生後,節點 1 可以繼續註冊新用戶,節點 2 無法註冊新用戶(這裏就是不符合 A 的原因,因爲節點 2 收到註冊請求後會返回 error),此時節點 1 可以將新註冊但未同步到節點 2 的用戶記錄到日誌中。當分區恢復後,節點 1 讀取日誌中的記錄,同步給節點 2,當同步完成後,節點 1 和節點 2 就達到了同時滿足 CA 的狀態。

而對於用戶信息數據,假設我們選擇了 AP,則分區發生後,節點 1 和節點 2 都可以修改用戶信息,但兩邊可能修改不一樣。例如,用戶在節點 1 中將愛好改爲“旅遊、美食、跑步”,然後用戶在節點 2 中將愛好改爲“美食、遊戲”,節點 1 和節點 2 都記錄了未同步的愛好數據,當分區恢復後,系統按照某個規則來合併數據。例如,按照“最後修改優先規則”將用戶愛好修改爲“美食、遊戲”,按照“字數最多優先規則”則將用戶愛好修改爲“旅遊,美食、跑步”,也可以完全將數據衝突報告出來,由人工來選擇具體應該採用哪一條。

ACID

ACID 是數據庫管理系統爲了保證事務的正確性而提出來的一個理論,ACID 包含四個約束,下面我來解釋一下。

1.Atomicity(原子性)

一個事務中的所有操作,要麼全部完成,要麼全部不完成,不會在中間某個環節結束。事務在執行過程中發生錯誤,會被回滾到事務開始前的狀態,就像這個事務從來沒有執行過一樣。

2.Consistency(一致性)

在事務開始之前和事務結束以後,數據庫的完整性沒有被破壞。

3.Isolation(隔離性)

數據庫允許多個併發事務同時對數據進行讀寫和修改的能力。隔離性可以防止多個事務併發執行時由於交叉執行而導致數據的不一致。事務隔離分爲不同級別,包括讀未提交(Read uncommitted)、讀提交(read committed)、可重複讀(repeatable read)和串行化(Serializable)。

4.Durability(持久性)

事務處理結束後,對數據的修改就是永久的,即便系統故障也不會丟失。

可以看到,ACID 中的 A(Atomicity)和 CAP 中的 A(Availability)意義完全不同,而 ACID 中的 C 和 CAP 中的 C 名稱雖然都是一致性,但含義也完全不一樣。ACID 中的 C 是指數據庫的數據完整性,而 CAP 中的 C 是指分佈式節點中的數據一致性。再結合 ACID 的應用場景是數據庫事務,CAP 關注的是分佈式系統數據讀寫這個差異點來看,其實 CAP 和 ACID 的對比就類似關公戰秦瓊,雖然關公和秦瓊都是武將,但其實沒有太多可比性。

BASE

BASE 是指基本可用(Basically Available)、軟狀態( Soft State)、最終一致性( Eventual Consistency),核心思想是即使無法做到強一致性(CAP 的一致性就是強一致性),但應用可以採用適合的方式達到最終一致性。

1. 基本可用(Basically Available)

分佈式系統在出現故障時,允許損失部分可用性,即保證核心可用。

這裏的關鍵詞是“部分”和“核心”,具體選擇哪些作爲可以損失的業務,哪些是必須保證的業務,是一項有挑戰的工作。例如,對於一個用戶管理系統來說,“登錄”是核心功能,而“註冊”可以算作非核心功能。因爲未註冊的用戶本來就還沒有使用系統的業務,註冊不了最多就是流失一部分用戶,而且這部分用戶數量較少。如果用戶已經註冊但無法登錄,那就意味用戶無法使用系統。例如,充了錢的遊戲不能玩了、雲存儲不能用了……這些會對用戶造成較大損失,而且登錄用戶數量遠遠大於新註冊用戶,影響範圍更大。

2. 軟狀態(Soft State)

允許系統存在中間狀態,而該中間狀態不會影響系統整體可用性。這裏的中間狀態就是 CAP 理論中的數據不一致。

3. 最終一致性(Eventual Consistency)

系統中的所有數據副本經過一定時間後,最終能夠達到一致的狀態。

這裏的關鍵詞是“一定時間” 和 “最終”,“一定時間”和數據的特性是強關聯的,不同的數據能夠容忍的不一致時間是不同的。舉一個微博系統的例子,用戶賬號數據最好能在 1 分鐘內就達到一致狀態,因爲用戶在 A 節點註冊或者登錄後,1 分鐘內不太可能立刻切換到另外一個節點,但 10 分鐘後可能就重新登錄到另外一個節點了;而用戶發佈的最新微博,可以容忍 30 分鐘內達到一致狀態,因爲對於用戶來說,看不到某個明星發佈的最新微博,用戶是無感知的,會認爲明星沒有發佈微博。“最終”的含義就是不管多長時間,最終還是要達到一致性的狀態。

BASE 理論本質上是對 CAP 的延伸和補充,更具體地說,是對 CAP 中 AP 方案的一個補充。前面在剖析 CAP 理論時,提到了其實和 BASE 相關的兩點:

  • CAP 理論是忽略延時的,而實際應用中延時是無法避免的。

這一點就意味着完美的 CP 場景是不存在的,即使是幾毫秒的數據複製延遲,在這幾毫秒時間間隔內,系統是不符合 CP 要求的。因此 CAP 中的 CP 方案,實際上也是實現了最終一致性,只是“一定時間”是指幾毫秒而已。

  • AP 方案中犧牲一致性只是指分區期間,而不是永遠放棄一致性。

這一點其實就是 BASE 理論延伸的地方,分區期間犧牲一致性,但分區故障恢復後,系統應該達到最終一致性。

綜合上面的分析,ACID 是數據庫事務完整性的理論,CAP 是分佈式系統設計理論,BASE 是 CAP 理論中 AP 方案的延伸。

小結

今天我爲你講了深入理解 CAP 理論所需要特別關注的細節點,以及 ACID 和 BASE 兩個相似的術語,這些技術細節在架構設計中非常關鍵,希望對你有所幫助。

這就是今天的全部內容,留一道思考題給你吧,假如你來設計電商網站的高可用系統,按照 CAP 理論的要求,你會如何設計?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章