0%

[架構設計] 分散式架構設計中的 CAP 理論

CAP 理論

CAP 理論演進

version 1

Robert Greiner 對於 CAP 理論的第一版解釋

Any distributed system cannot guaranty C, A, and P simultaneously.

對於一個分佈式計算系統,不可能同時滿足一致性(Consistence)、可用性(Availability)、分區容錯性(Partition Tolerance)三個設計約束。

version 2

Robert Greiner 對於 CAP 理論的第二版解釋

In a distributed system (a collection of interconnected nodes that share data.), you can only have two out of the following three guarantees across a write/read pair: Consistency, Availability, and Partition Tolerance - one of them must be sacrificed.

在一個分散式系統(指互相連接並共享資料的節點的集合)中,當涉及讀寫操作時,只能保證一致性(Consistence)、可用性(Availability)、分區容錯性(Partition Tolerance)三者中的兩個,另外一個必須被犧牲。

差異之處

  • CAP 理論探討的分散式系統,強調了兩點:interconnectedshare data

  • 分散式系統並不一定會互聯和共享資料

    Memcache 的集群,相互之間就沒有連接和共享資料,因此 Memcache 集群這類分散式系統就不符合 CAP 理論探討的對象;而 MySQL 集群就是互聯和進行資料複製的,因此是 CAP 理論探討的對象

  • CAP 關注的是對資料的讀寫操作,而不是分散式系統的所有功能,例如:ZooKeeper 的選舉機制就不是 CAP 探討的對象

CAP 內容

Consistency (一致性)

  • 站在 client 的角度來觀察系統的行為和特徵

  • 從 client 的讀寫角度來描述資料一致性

  • 在事務執行過程中,系統其實處於一個不一致的狀態,不同的節點的資料並不完全一致,但 client 讀操作能夠獲取最新的寫結果就沒有問題

Availability (可用性)

  • 只有非故障節點才能滿足可用性要求,如果節點本身就故障了,發給節點的請求不一定能得到一個響應

  • 不能超時、不能出錯,結果是合理的(但結果有可能因為資料尚未同步完整,導致資料是不正確的)

Partition Tolerance (分區容忍性)

  • 只有返回 reasonable response 才是 function(可用功能),而 function 強調”發揮作用” & “履行職責”

  • 即發生了分區現象,不管是什麼原因,可能是網路封包遺失,也可能是連接中斷,還可能是擁塞,只要導致了網路分區,就通通算在裡面

CAP 應用

  • 雖然 CAP 理論定義是三個要素中只能取兩個,但放到分佈式環境下來思考,會發現必須選擇 P(分區容忍)要素,因為網路本身無法做到 100% 可靠

  • 分散式系統理論上不可能選擇 CA 架構,只能選擇 CP 或者 AP 架構

討論整理精華

  • 「一致性」和「可用性」都應該站在 client 側去審視;而「分區容忍性」則是 cluster 在遇到網路分區的問題時,選擇如何去影響 client 感知到的「一致性」和「可用性」

  • P 要求分佈式和資料同步,C 要求資料完全一致,A 要求返回及時

  • CAP 理論是忽略延時的,這就是說理論做了一個假設,只要網路通資料就會一致,這也是實際應用CAP時容易踩的坑

  • paxos 協議是為了解決資料一致性而設計的算法,主要是通過投票選舉的方式決定出主節點,之後就以主節點的資料為準,因而屬於 PC 模式

  • 不是必然選擇 P,而是說分散式系統必然會出現分區的情況,你要選擇的是要不要”容忍”,無法容忍分區,那就在出現分區的時候系統不對外提供服務

  • P 是說是否允許網路分區,允許的話可以繼續提供服務,不允許的話,一旦出現分區,系統所有節點停止服務

  • 一個分散式系統當P發生時,C 和 A 二者只能選其一

    • P:分區容錯性,是站在服務器的角度來講的
    • C:資料一致性,是站在 client 的角度來講的
    • A:系統可用性,是站在 client 的角度來講的

在通過網路構建的分散式系統中,P 是不能 100% 避免的,所以,我們只能考慮,當 P 發生時是要 C 還是要 A

  • 區塊鏈不要求所有人同一時刻看到的資料一致,而且某個節點掛掉後其它節點還是可以修改資料,因此是 AP 系統

  • CAP 要求節點間針對同一份資料進行複製和備份

  • 網路分區 => 假設本來5台機器網路都是通的,現在由於交換機故障,其中3台聯通形成小團體A,另外兩台聯通形成小團體B,但是 A 和 B 不聯通

CAP 細節

  • 理論的優點在於清晰簡潔、易於理解,但缺點就是高度抽象化,省略了很多細節,導致在將理論應用到實踐時,由於各種複雜情況,可能出現誤解和偏差

  • 談到資料一致性時,CAP、ACID、BASE 難免會被拿出來討論,原因在於這三者都是和資料一致性相關的理論

CAP 關鍵細節點

CAP 關注的粒度是資料,而不是整個系統

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

  • 實際設計過程中,每個系統不可能只處理一種資料,而是包含多種類型的資料,有的資料必須選擇 CP,有的資料必須選擇 AP

  • 如果我們做設計時,從整個系統的角度去選擇 CP 還是 AP,就會發現顧此失彼,無論怎麼做都是有問題的

用戶管理系統為例,用戶管理系統包含用戶賬號資料(用戶 ID、密碼)、用戶信息資料(暱稱、興趣、愛好、性別、自我介紹等),前者會選擇 CP,後者會選擇 AP;但所有資料都選擇 CP or AP 都是不合理的

CAP 是忽略網路延遲的

  • CAP 理論中的 C 在實踐中是不可能完美實現的,在資料複製的過程中,節點 A 和節點 B 的資料並不一致

  • 對於某些嚴苛的業務場景,例如和金錢相關的用戶餘額,或者和搶購相關的商品庫存,技術上是無法做到分佈式場景下完美的一致性的

  • 這並不意味著這類系統無法應用分佈式架構,只是說”單個用戶餘額、單個商品庫存”無法做分佈式,但系統整體還是可以應用分佈式架構的

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

  • 架構設計的時候既要考慮分區發生時選擇 CP 還是 AP,也要考慮分區沒有發生時如何保證 CA

  • 即使是實現 CA,不同的資料實現方式也可能不一樣 (例如:用戶帳號資料可用 Message Queue 來實現,用戶消息資料可用 DB 同步來實現)

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

  • 分區期間放棄 C 或者 A,並不意味著永遠放棄 C 和 A,我們可以在分區期間進行一些操作,從而讓分區故障解決後,系統能夠重新達到 CA 的狀態

  • 分區恢復後的資料不一致,可以是軟體 or 工具自動處理,或是人工處理

ACID

基本原理

ACID 是資料庫管理系統為了保證事務的正確性而提出來的一個理論,包含四個限制:

  • Atomicity:一個事務中的所有操作,要嘛全部完成,要嘛全部都沒完成

  • Consistency:在事務開始之前和事務結束以後,資料庫的完整性沒有被破壞

  • Isolation:防止多個事務並發執行時由於交叉執行而導致資料的不一致

  • Durability事務處理結束後,對資料的修改就是永久的,即便系統故障也不會丟失

與 CAP 的差異

  • ACID 中的 A(Atomicity)和 CAP 中的 A(Availability)意義完全不同

  • ACID 中的 C 是指資料庫的資料完整性,而 CAP 中的 C 是指分佈式節點中的資料一致性

  • ACID 的應用場景是資料庫事務,CAP 關注的是分散式系統資料讀寫這個差異點來看

BASE

  • 核心思想是即使無法做到強一致性(CAP 的一致性就是強一致性),但應用可以採用適合的方式達到最終一致性

  • BASE 理論本質上是對 CAP 的延伸和補充

基本可用(Basically Available)

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

  • 具體選擇哪些作為可以損失的業務,哪些是必須保證的業務,是一項有挑戰的工作

    例如,對於一個用戶管理系統來說,”登錄”是核心功能,而”註冊”可以算作非核心功能

軟狀態(Soft State)

  • 允許系統存在中間狀態,而該中間狀態不會影響系統整體可用性

  • 就是 CAP 理論中的資料不一致

最終一致性(Eventual Consistency)

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

  • 一定時間”和資料的特性是強關聯的,不同的資料能夠容忍的不一致時間是不同的

討論整理精華

  • ACID 是資料庫事務完整性的理論,CAP 是分散式系統設計理論,BASE 是 CAP 理論中 AP 方案的延伸

  • 一份資料在多個節點有但不是所有節點都有,這是非對稱集群;例如 Elasticsearch;所有資料在所有節點都有,這是對稱集群,例如 zookeeper

  • 任何一個正常運行的分散式系統,起源於 CA 狀態,中間(發生分區時)可能經過 CP 和 AP 狀態,最後回到 CA 狀態;所以一個分散式系統,需要考慮實現三點:

    • 正常運行時的 CA 狀態。
    • 發生分區時轉變為 CP 或 AP 狀態
    • 分區解決時如何恢復為 CA 狀態

重點整理

設計分散式系統的兩大初衷:橫向擴展(scalability)和高可用性(availability)

“橫向擴展”是為了解決單點瓶頸問題,進而保證高並發量下的「可用性」;”高可用性”是為了解決單點故障(SPOF)問題,進而保證部分節點故障時的「可用性」。由此可以看出,分散式系統的核心訴求就是「可用性」。這個「可用性」正是 CAP 中的 A:用戶訪問系統時,可以在合理的時間內得到合理的響應。

為了保證「可用性」,一個分散式系統通常由多個節點組成。這些節點各自維護一份資料,但是不管用戶訪問到哪個節點,原則上都應該讀取到相同的資料。為了達到這個效果,一個節點收到寫入請求更新自己的資料後,必須將資料同步到其他節點,以保證各個節點的資料「一致性」。這個「一致性」正是 CAP 中的 C:用戶訪問系統時,可以讀取到最近寫入的資料。

需要注意的是:CAP 並沒有考慮資料同步的耗時,所以現實中的分散式系統,理論上無法保證任何時刻的絕對「一致性」;不同業務系統對上述耗時的敏感度不同。

分散式系統中,節點之間的資料同步是基於網路的。由於網路本身固有的不可靠屬性,極端情況下會出現網路不可用的情況,進而將網路兩端的節點孤立開來,這就是所謂的”網路分區”現象。”網路分區”理論上是無法避免的,雖然實際發生的概率較低、時長較短。沒有發生”網路分區”時,系統可以做到同時保證「一致性」和「可用性」。

電商 CAP 分析 (1)

  • 一個電商網站核心模組有會員,訂單,商品,支付,促銷管理等

  • 對於會員模組,包括登錄,個人設置,個人訂單,購物車,收藏夾等,這些模組保證 AP,資料短時間不一致不影響使用

  • 訂單模組的下單付款扣減庫存操作是整個系統的核心,CA 都需要保證,但在極端情況下犧牲 P 是可以的

  • 商品模組的商品上下架和庫存管理保證 CP,搜索功能因為本身就不是實時性非常高的模組,所以保證 AP 就可以了

  • 促銷是短時間的資料不一致,結果就是優惠信息看不到,但是已有的優惠要保證可用,而且優惠可以提前預計算,所以可以保證 AP

  • 現在大部分的電商網站對於支付這一塊是獨立的系統,或者使用第三方的支付寶,微信。其實 CAP 是由第三方來保證的,支付系統是一個對 CAP 要求極高的系統,C 是必須要保證的,AP 中 A 相對更重要,不能因為分區,導致所有人都不能支付

電商 CAP 分析 (2)

  • 電商網站核心功能有用戶、產品、訂單、支付、庫存,相應的資料有用戶、產品、訂單、支付、庫存

  • 對於用戶資料,選擇 CP;因為用戶註冊後,可能幾分鐘後重新登錄,所以需要滿足一致性;在網路出現分區時,因為需要滿足一致性而暫時不能提供寫服務,所以無法滿足可用性;對於分區容錯性,只要能返回一個合理的響應就能滿足,這一點能很好滿足

  • 對於產品資料,無需滿足一致性,所以選擇 AP

  • 對於訂單資料,業務需要滿足一致性,所以選擇 CP

  • 對於支付資料,業務需要滿足一致性,所以選擇 CP

  • 對於庫存資料,業務需要滿足一致性,所以選擇 CP

FMEA 方法,排除架構可用性隱患的利器

FMEA 介紹

  • FMEA(Failure mode and effects analysis,故障模式與影響分析)通過對系統範圍內潛在的故障模式加以分析,並按照嚴重程度進行分類,以確定失效對於系統的最終影響

  • FMEA 是一套分析和思考的方法,而不是某個領域的技能或者工具

  • 在軟體架構設計領域,FMEA 並不能指導我們如何做架構設計,而是當我們設計出一個架構後,再使用 FMEA 對這個架構進行分析,看看架構是否還存在某些可用性的隱患

FMEA 方法

在架構設計領域,FMEA 的具體分析方法是:

  • 給出初始的架構設計圖。
  • 假設架構中某個部件發生故障
  • 分析此故障對系統功能造成的影響
  • 根據分析結果,判斷架構是否需要進行優化

功能點

指的是從用戶角度來看的,而不是從系統各個模組功能點劃分來看的

故障模式

  • 指的是系統會出現什麼樣的故障,包括故障點和故障形式

  • 不需要給出真正的故障原因,我們只需要假設出現某種故障現象即可,例如 MySQL 響應時間達到 3 秒

  • 故障模式的描述要儘量精確,多使用量化描述,避免使用泛化的描述

故障影響

  • 當發生故障模式中描述的故障時,功能點具體會受到什麼影響

  • 常見的影響有:功能點偶爾不可用、功能點完全不可用、部分用戶功能點不可用、功能點響應緩慢、功能點出錯等

  • 故障影響也需要儘量準確描述,例如,推薦使用”20% 的用戶無法登錄”,而不是”大部分用戶無法登錄”

嚴重程度

  • 指站在業務的角度故障的影響程度,一般分為”致命 / 高 / 中 / 低 / 無”五個檔次

  • 按公式進行評估:嚴重程度 = 功能點重要程度 × 故障影響範圍 × 功能點受損程度

  • 對於某個故障的影響到底屬於哪個檔次,有時會出現一些爭議,沒有絕對標準

故障原因

為何要列出故障原因?

  • 不同的故障原因發生概率不相同

    例如:導致 MySQL 查詢響應慢的原因可能是 MySQL bug,也可能是沒有索引

  • 不同的故障原因檢測手段不一樣

    例如:磁盤壞道 & slow query 都會導致 MySQL 響應慢,但檢測方式就不會相同

  • 不同的故障原因的處理措施不一樣

    例如:如果是 MySQL bug,我們的應對措施只能是升級 MySQL 版本;如果是沒有索引,我們的應對措施就是增加索引

故障概率

  • 指某個具體故障原因發生的概率,一般分為”高 / 中 / 低”

  • 需要關注的重點:

    • 硬體:隨著使用時間推移,故障概率會越來越高
    • 開源系統:成熟的開源系統 bug 率低,剛發佈的開源系統 bug 率相比會高一些
    • 自研系統:成熟的自研系統故障概率會低,而新開發的系統故障概率會高
  • 高中低是相對的,只是為了確定優先級以決定後續的資源投入,沒有必要絕對量化

風險程度

  • 風險程度就是綜合嚴重程度和故障概率來一起判斷某個故障的最終等級

  • 風險程度 = 嚴重程度 × 故障概率

  • 同樣的故障影響,不同的故障原因有不同的概率,最終得到的風險級別就是不同的

已有措施

針對具體的故障原因,系統現在是否提供了某些措施來應對,包括:

  • 檢測告警:檢測故障,然後告警,系統自己不針對故障進行處理,需要人工干預
  • 容錯:檢測到故障後,系統能夠通過備份手段應對
  • 自恢復:檢測到故障後,系統能夠自己恢復

規避措施

為了降低故障發生概率而做的一些事情,可以是技術手段,也可以是管理手段,例如:

  • 技術手段:為了避免新引入的 MongoDB 丟失資料,在 MySQL 中冗餘一份

  • 管理手段:為了降低磁盤壞道的概率,強制統一更換服務時間超過 2 年的磁盤

解決措施

  • 為了能夠解決問題而做的一些事情,一般都是技術手段,例如:

    • 為了解決密碼暴力破解,增加密碼重試次數限制
    • 為了解決從資料庫中導出資料導致資料洩露,將資料庫中的敏感資料加密保存
    • 為了解決非法訪問,增加白名單控制
  • 如果某個故障既可以採取規避措施,又可以採取解決措施,那麼我們會優先選擇解決措施,畢竟能解決問題當然是最好的

後續規劃

  • 針對這些不足的地方,再結合風險程度進行排序,給出後續的改進規劃

  • 這些規劃既可以是技術手段,也可以是管理手段;可以是規避措施,也可以是解決措施。

  • 同時需要考慮資源的投入情況,優先將風險程度高的系統隱患解決

References