分佈式系統:CAP 理論的前世今生

CAP 理論是分佈式系統設計中的一個重要理論,雖然它為系統設計提供了非常有用的依據,但是也帶來了很多誤解。本文將從 CAP 誕生的背景說起,然後對理論進行解釋,最後對 CAP 在當前背景下的一些新理解進行分析,澄清一些對 CAP 的誤解。

CAP 理論誕生的背景

CAP 理論的是在“數據一致性 VS 可用性”的爭論中產生。CAP 的作者 Brewer 在 90 年代的時候就開始研究基於集群的跨區域系統(實質上是早期的雲計算),對於這類系統而言,系統可用性是首要目標,因此他們採用了緩存或者事後更新的方式來優化系統的可用性。儘管這些方法提升了系統的可用性,但是犧牲了系統數據一致性。

Brewer 在 90 年代提出了 BASE 理論(基本可用、軟狀態、最終一致性),這在當時還不怎麼被接受。因為大家還是比較看重 ACID 的優點,不願意放棄強一致性。因此,Brewer 提出了 CAP 理論,目的就是為了開闊分佈式系統的設計空間,通過“三選二”的公式,解放思想,不要只抓著一致性不放。

理解了 CAP 誕生的背景,我們才能更加深入的理解 CAP 理論,以及它帶來的啟示。“三選二”的觀點雖然幫助大家開拓了設計思路,但是也帶來了很多誤解。下面我們會逐一分析,首先來看一下 CAP 理論的解釋。

CAP 理論的經典解釋

CAP 定理是分佈式系統設計中最基礎,也是最為關鍵的理論。它指出,分佈式數據存儲不可能同時滿足以下三個條件。

  • 一致性(Consistency):每次讀取要麼獲得最近寫入的數據,要麼獲得一個錯誤。
  • 可用性(Availability):每次請求都能獲得一個(非錯誤)響應,但不保證返回的是最新寫入的數據。
  • 分區容忍(Partition tolerance):儘管任意數量的消息被節點間的網絡丟失(或延遲),系統仍繼續運行。

CAP 定理表明,在存在網絡分區的情況下,一致性和可用性必須二選一。當網絡發生分區(不同節點之間的網絡發生故障或者延遲較大)時,要麼失去一致性(允許不同分區的數據寫入),要麼失去可用性(識別到網絡分區時停止服務)。而在沒有發生網絡故障時,即分佈式系統正常運行時,一致性和可用性是可以同時被滿足的。這裡需要注意的是,CAP 定理中的一致性與 ACID 數據庫事務中的一致性截然不同。ACID 的 C 指的是事務不能破壞任何數據庫規則,如鍵的唯一性。與之相比,CAP 的 C 僅指單一副本這個意義上的一致性,因此只是 ACID 一致性約束的一個嚴格的子集。

CAP 理論看起來難理解,其實只要抓住一個核心點就能推導出來,不用死記硬背。在出現網絡分區的時候,

  • 如果系統不允許寫入,那麼意味著降低了系統的可用性,但不同分區的數據能夠保持一致,即選擇了一致性。
  • 如果系統允許寫入,那麼意味著不同分區之間的數據產生不一致,系統可用性得到保障,即選擇可用性。

CAP 的新理解

CAP 經常被誤解,很大程度上是因為在討論 CAP 的時候可用性和一致性的作用範圍往往都是含糊不清的。如果不先定義好可用性、一致性、分區容忍在具體場景下的概念,CAP 實際上反而會束縛系統設計的思路。首先,由於分區很少發生,那麼在系統不存在分區的情況下沒什麼理由犧牲 C 或 A。其次,C 與 A 之間的取捨可以在同一系統內以非常細小的粒度反覆發生,而每一次的決策可能因為具體的操作,乃至因為牽涉到特定的數據或用戶而有所不同。最後,這三種性質都可以在程度上都可以進行度量,並不是非黑即白的有或無。可用性顯然是在 0% 到 100% 之間連續變化的,一致性分很多級別,連分區也可以細分為不同含義,如系統內的不同部分對於是否存在分區可以有不一樣的認知。

什麼是分區容忍

在現實世界中,正常情況下分佈式系統各個節點之間的通信是可靠的,不會出現消息丟失或者延遲很高的情況,但是網絡是不可靠的,總會偶爾出現消息丟失或者消息延遲很高的情況,這個時候不同區域的節點之間在一段時間內就會出現無法通信的情況,也就是發生了分區。

分區容忍就是指分佈式系統在出現網絡分區的時候,仍然能繼續運行,對外提供服務。注意,這裡所說的仍然能夠對外提供服務跟可用性的要求不一樣,可用性要求的是對於任意請求都能得到響應,意味著即使出現網絡分區所有節點都能夠提供服務。而分區容忍的重點在於出現網絡分區之後,系統仍然是可用的(包括部分可用)。

舉個例子:使用 Paxos 進行數據複製的系統就是典型的 CP 系統,即使出現網絡分區,主分區也能夠提供服務,所以它是分區容忍的。再舉個反例:使用 2PC 進行數據複製的系統沒有分區容忍的特性,當出現網絡分區時,整個系統都會阻塞。

可用性的範圍

可用性其實很直觀:每次請求都能獲得一個(非錯誤)響應,但不保證返回的是最新寫入的數據。換一個說法就是對於分佈式系統中的每個節點,都能夠對外部請求做出響應,但不要求一致性。

經常讓我們疑惑的問題是衡量系統可用性的標準是什麼?其實關鍵點在於可用性的範圍,脫離了具體場景下的可用性範圍是沒有意義的。討論可用性是要有具體場景來劃分邊界的,簡單的認為某個算法是滿足可用性要求其實並不嚴謹,因為在工程實現中會有很多的技巧去彌補修正。

舉個例子:谷歌文檔就是非常典型的 AP 系統,它在網絡斷了的情況下也能夠使用。訣竅在於它在發現網絡斷了之後會進入離線模式,允許用戶繼續進行編輯,然後在網絡恢復之後再對修改的內容進行合併處理。可以發現對於谷歌文檔來說,用戶的瀏覽器也是它系統的一個節點,當出現網絡分區時,它仍然能夠為用戶提供服務,但是代價是放棄了一致性,因為用戶做的修改只有本地知道,服務端是不清楚的。所以在這個例子裡面,可用性的範圍是包括了用戶瀏覽器在內的,不是我們常規理解的分佈式系統的節點一定就是服務端的機器。

值得注意的是在現實世界中,我們一般不會去追求完美的可用性,所以一般的說法是高可用,即儘可能保證更多的節點服務可用。這也是為什麼 Paxos 這類的一致性算法越來越流行的原因之一。

一致性的範圍

討論一致性的時候必須要明確一致性的範圍,即在一定的邊界內狀態是一致的,超出邊界之外的一致性是無從談起的。比如 Paxos 在發生網絡分區的時候,在一個主分區內可以保證完備的一致性和可用性,而在分區外服務是不可用的。值得注意的是,當系統在分區的時候選擇了一致性,也就是 CP,並不意味著完全失去了可用性,這取決於一致性算法的實現。比如標準的兩階段提交發生分區的時候是完全不可用的,而 Paxos 則保證了主分區的一致性和可用性。

經過上面的討論可以發現,可用性的範圍要求比一致性的範圍要求要更嚴格,CAP 理論中的可用性要求的是整個系統的可用性,即使出現部分節點不可用也算是違反了可用性約束。而一致性的要求則沒有那麼高,發生網絡分區的時候只要保證主分區數據一致性,也認為系統是符合一致性約束的。為什麼這麼說呢?因為當出現網絡分區的時候,客戶端只要通過訪問主分區就能得到最新的值(訪問超過半數以上節點,如果值都相同說明訪問的數據是最新的),此時系統是滿足 CAP 理論中一致性的要求的。

管理分區

網絡分區是分佈式系統中必然發生的事情,經典的 CAP 理論是忽略網絡延遲的,但是在現實世界中,網絡延遲跟分區密切相關。也就是說當系統在有限的時間內無法通信達成一致(網絡延遲很高),就意味著發生了分區。此時就需要在一致性和可用性之間做出選擇:選擇繼續重試就意味著選擇一致性,放棄可用性;放棄數據一致性讓操作完成就意味著選擇了可用性。值得注意的是在分區的時候放棄數據一致性並不是意味著完全不管,一般工程實現會採用重試的方式達到最終一致性。

通過上面的分析可以發現,平衡分區期間可用性和一致性的影響是分佈式系統設計中的關鍵問題。因此,管理分區不僅是需要主動發現分區,還需要針對分區期間產生的影響準備恢復過程。也就是說我們可以從另一個角度來應用 CAP 理論:系統進入分區模式的時候,如何在一致性和可用性之間做出選擇。

管理分區有三個步驟:

分佈式系統:CAP 理論的前世今生

  • 檢測到分區開始
  • 明確進入分區模式,限制某些操作
  • 當通信恢復後啟動分區恢復過程

當系統進入分區模式之後,有兩種選擇:

  • 選擇一致性:例如 Paxos 算法,只有大多數的主分區能夠進行操作,其他分區不可用,當網絡恢復之後少數節點跟多數節點同步數據。
  • 選擇可用性:例如谷歌文檔,出現分區時進入離線模式,等網絡恢復了客戶端跟服務端數據進行合併恢復。

總結

  • 理論抽象於現實,服務於現實,但絕不等於現實。對 CAP 理論“三選二”的誤解就源於我們經常把理論等同於現實。CAP 的誕生主要是為了拓寬設計思路,不要侷限在強一致性的約束中。簡單的把“三選二”進行套用反而限制了設計思路。在現實世界中,不同業務場景對可用性和一致性的要求不一樣,並且一致性和可用性的範圍和區間是動態變化的,並不是非此即彼。因此,準確理解 CAP 理論,從管理分區的角度出發,結合具體的業務場景,才能做出更好的系統設計。


分享到:


相關文章: