CAP定理101—分散式系統,有一好沒兩好

Cap Theorem 101

YH Yu
後端新手村
8 min readJun 7, 2019

--

本文屬於系列:系統設計學習地圖

故事從一個簡單的小系統開始,這個系統有個小資料庫,一切單純而美好。但隨著系統的使用者與資料越來越多,小系統慢慢變大,資料庫也開始逐漸不堪負荷。於是我們開始幫資料庫升級(更多的RAM、更多的空間),但硬體的升級是有極限的,終究還是遇到了瓶頸。

我們決定加一個新的資料庫幫忙分擔流量。每當使用者需要存取資料時,就會連結到其中一個資料庫。不論哪個資料庫有更新,它都會將資料同步給對方。使用者不需改變原有行為,但現在我們能處理兩倍的流量!

我們的資料庫正式邁入了分散式的系統架構(distributed system),一個資料庫變兩個,還是不夠就再變四個,一切再度單純而美好。

分散式系統之挑戰:網路問題導致的資料分區(Partition)

天有不測風雲,就算機率再小,壞事總有機會發生。有天資料庫間的網路連線發生了些問題。導致資料在傳輸過程中丟了,或是網路直接斷了等等。總之彼此沒有辦法正常同步資料了。

想像一下,今天我們有四個資料庫,A、B在台北,C、D在台中。有位使用者連線到A更新了某筆資料,同在台北的B也順利地同步了,但要同步到C、D時發現台北到台中的網路出了問題…

現在兩個地區的資料不再一致了。對使用者來說,如果他下次連線進到C或D,就像看到另一個資料庫似的,之前更新的資料不見了!這就是網路問題導致的資料分區。該怎麼辦呢?CAP定理(CAP theorem)就是在探討這個議題。

什麼是CAP定理

CAP是下列三個單字的首字縮寫:

  • 一致性(Consistency):使用者讀到的”總是”最新的資料
  • 可用性(Availability):使用者的請求”總是”可以獲得回應,也就是可以正常讀寫(回傳錯誤訊息並不算滿足可用性)
  • 分區容錯性(Partition tolerance):就算網路出現問題導致資料分區,整個系統仍然要可以繼續運作

CAP定理告訴我們,在分散式系統中,這三個特性只能同時滿足兩個。也就是說,我們必須要做出取捨(trade-off)

在系統設計的範疇中,幾乎所有的架構方式都是在做出某種取捨,有一好沒兩好。如果在某個問題上,存在完美的選擇,那麼就根本無需討論了對吧?

既然要三選二,那麼我們就先從滿足CA(一致性、可用性),捨棄P(分區容錯性)的系統看起吧!但馬上就發現哪裡怪怪的?想要同時滿足這兩個條件的的話,系統就決不能出現先前提過的資料分區。也就是資料庫間的網路狀態必須永遠是完美的!

很明顯地,這種假設太不現實。唯一解法是我們退回單一資料庫,那麼的確可以不用考慮資料庫間的網路問題。但CAP定理討論的就是分散式系統,單一資料庫下引進CAP定理沒有太大意義!所以CA其實不太算一種”選擇”。

CP vs AP

既然一定要考慮到網路問題,所以P(分區容錯性)無法捨棄。在這個前提下,我們接著在C(一致性)和A(可用性)之間做抉擇。

先看看滿足CP(一致性、分區容錯性)的系統如何運作。使用者連線到其中一個資料庫,想要讀取或寫入資料。若此時發現無法與另一個資料庫同步,使用者的請求就會失敗!

沒有任何一個資料庫會片面地改變資料的狀態。我們保證了資料的C(一致性),但犧牲了使用者總是能得到回應的A(可用性)。

再來看看滿足AP(可用性、分區容錯性)的系統。使用者連線到其中一個資料庫想要更新資料,此時該資料庫無法同步另一個資料庫。但它仍然更新了這筆資料並告知使用者更新成功。

若很不幸地,下次使用者連線到另一個資料庫想要拿資料,就會拿到舊的資料!我們保證了系統的A(可用性),讓使用者總是能得到回應。但犧牲了資料的C(一致性)。

最終一致性(Eventually Consistency)

根據CAP定理,我們要不是選擇C(一致性)而放棄A(可用性),就是反過來。但現實世界的情況,往往不是這麼地非黑即白。依照不同的商業邏輯與使用情境,在兩者間取得平衡的設計是非常普遍的。

舉例來說,對於C(一致性)而言,我們把CAP定理所定義的一致性稱為強一致性(strong consistency)。適合處理像是金錢、付款這種對資料同步高度要求的任務。但相對的,擴展性、可用性就會比較侷限(想像一下,若資料庫的數量持續地增加,同步所有資料的成本也會不斷上升)。

與強一致性相對的是所謂的最終一致性(eventually consistency)。當使用者更新某筆資料時,也許因為網路暫時中斷或延遲,沒有即時同步到另一個資料庫。我們還是讓其他使用者可以繼續存取資料(不是最新的也沒關係),但最終,我們保證這筆資料一定會同步(最後的結果還是對的)。

此外,雖然網路發生問題聽起來很嚴重,但其實往往持續不到幾秒。所以最終一致性是一種很務實的做法,適合資料更新可以有一點延遲的場合,例如文章的新留言、影片總共觀看人數等等。

最終一致性只是個例子。說明實務上,系統在一致性和可用性間,會鬆綁特性來取得平衡。雖然不符合CAP定理的原始定義,但它們都運作的很好。

現今主流的資料庫技術大多無法歸類為純粹的CP或AP。只能說在根本的設計上,它們為了解決特定的問題可能會偏向其中一方。但一般都會再提供部分彈性,讓我們有機會依據自己的需求來做調整。

推薦閱讀:請停止稱呼某資料庫為CP或AP

CAP vs ACID

在學習CAP定理的過程中,參考了許多文章和討論。有時候CAP定理和ACID會放在一起比較,或是看到『CAP定理是NoSQL在用的,RDBMS要用ACID來看』這樣的說法。這裡做一下歸納並重新檢視自己的理解。

首先我們來看ACID的部分,ACID分別代表資料庫在寫入資料的過程中,所具備的四種特性,具體內容不在本文的討論範圍。但特別提一下它的C和CAP定理一樣寫做 consistency,但意義完全不同。

RDBMS(像是MySQL、PostgreSQL),必須要同時滿足ACID四種特性來提供一種稱為交易(transaction)的操作。所以RDBMS和ACID常一起出現。NoSQL則大多不保證同時滿足這四種特性,也不支援傳統上的交易操作,來換取像是擴展性、可用性等等。

由於NoSQL大多在最初就是用分散式的架構去設計的,而CAP定理就是在探討分散式系統的抉擇,這也是為什麼CAP定理常和NoSQL一起出現。

簡而言之,CAP定理和ACID的關係就是沒什麼關係!

總結

回顧一下,首先我們從單一系統開始,隨著流量增長,演變為分散式的系統架構。在分散式的系統架構下,必定會遇到網路問題導致的資料分區。CAP定理就是用來探討這種情況下,系統在設計上必須做出的取捨。其中CA的系統對於CAP定理來說意義不大,於是我們分別探討CP和AP的系統,所選擇的特性和做出的犧牲。

到這邊CAP定理基本上算是介紹完了。但現實世界的系統往往不是這麼非黑即白地歸類為CP或AP。最終一致性,可以用來說明在設計上,其實有許多的彈性來滿足不同的使用情境。最後則是補充常被錯誤比較的ACID。

在系統設計中,資料庫的地位可以說是重中之重。在選擇任何一種技術前,首先要明確地知道自己的需求、使用情境。然後預想所有可能的異常下,系統會表現出的行為。有沒有危害到重要的商業邏輯?如何處理和修復?每一種設計都有它想要解決的問題和必須做出的取捨,CAP定理只是其中一種思考方向而已。這個“思考的脈絡”才最重要的部分!

在找資料的過程中,總有種『一個CAP定理,各自解讀』的感覺。為此,甚至還有像是CAP-FAQ這樣,專門整理常見誤解的文章。本文的解釋可能也有不精確甚至錯誤的地方,若有人能指正我會非常感激!

如果這篇文章對你有所幫助的話,歡迎拍手讓我知道,最多可以拍50下喔👏👏

--

--

YH Yu
後端新手村

Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better.