CAP
CAP 理論是分布式系統中的一個老生常談的理論了,最早由 Eric Brewer 在一個講座中提出。在這個講座中,在傳統 ACID 理論以及當時比較流行但是比較抽象的的設計指導理論 BASE 理論(當時的 BASE 理論還很抽象,直到好幾年后才出現一份比較權威的被廣泛接受的 BASE 理論完整解釋和設計)的類比中,提出
- C(Consistency,一致性):在一個分布式的系統中,同一個數據的所有備份,在同一時刻是否有相同的值。也就是,對於同一個數據的讀寫,是否立刻對於所有副本都能看到一致的結果。一種比較常見的強一致性實現就是,在看到一致的結果之前,寫請求不返回,讀請求阻塞或者超時。
- A(Availability,可用性):在集群中一些節點故障時,集群還可以響應讀寫請求。
- P(Partition-tolerance,分區容忍性):分布式系統具有多個節點,如果節點間網絡中斷,就會造成分區。
並且提出了,CAP 並不能全部滿足,而是一般選兩個滿足
之后,Seth Gilbert 以及 Nancy Lynch 在一篇 Notes 中,證明了 CAP 並不能同時都滿足。並且,將 CAP 定義的更加清晰:
- C: 需要滿足原子一致性,也就是任何讀寫都是具有原子性的,也就是對於同一個數據的寫之后的讀取,一定能讀取到寫的值,也就是最新的值
- A:對於所有成功的請求,都需要在有限的時間內返回,也就是成功請求是有效的,可終止的。
- P:可能節點間傳輸丟失一些消息。
CA 系統
也就是不允許分區的系統,也其實就不是分布式系統,而是單機系統。例如單機數據庫,或者是共享存儲數據庫,比如 Aurora DB 類似的思路設計的數據庫,共享同一份存儲,上面建立不同的 MySQL 進程,一個 MySQL 讀寫,其他的只讀,由於使用的同一塊存儲,並且只有一個 MySQL 進程寫入,滿足 ACID 的事務特性,能保證強一致性,以及可用性。
CP 系統
也就是不要求高可用性,但是要求強一致性的系統,哪怕當前業務不可用,也不能出現數據不一致的情況。並且,如果節點間傳輸消息丟失導致沒有同步成功,或者重試,或者返回更新失敗,回滾更新請求。
CP 的一種實際應用就是分布式鎖,一般的,如果沒有獲取到鎖,或者獲取鎖失敗,我們都會選擇阻塞等待,或者直接失敗,而不會冒着可能會有並發危險而去執行業務。並且,分布式鎖必須保持所有節點看到的鎖狀態一致,不能有差異,否則認為獲取鎖失敗。
同時,大部分分布式數據庫都是 CP 系統,但是他們的一致性協議方案是不同的,常見的例如 Paxos,2PC,3PC,RAFT等等。
AP 系統
也就是要求高可用性,但是不用強一致性的系統。在這種情況下,一旦分區發生,節點間的數據可能不一致,每個節點用自己的本地數據繼續提供服務。這樣情況下,可能會出現數據不一致,系統一般會實現最終一致性。也就是在分區結束后,通過一些機制將數據同步。
基本上具有多層緩存的系統,都是 AP 的系統設計。例如 DNS,客戶端緩存,瀏覽器緩存以及進程內緩存等等。
一個 CP 與 AP 系統的對比
一個比較經典的例子就是 Zookeeper 作為注冊中心和 Eureka 作為注冊中心。
假設注冊中心有兩個接口,一個是注冊實例,一個是讀取實例。
如果以 Zookeeper 為注冊中心,對於注冊實例請求也就是更新請求,采用的是過半寫以及 2 PC 的同步機制。
只有過半 2PC 更新成功,這個注冊請求才成功,這樣讀取每個節點都會讀取到這個更新請求,否則會回滾已經更新的節點。並且每個節點數據是一致的。如果過半的節點不可用,那么整個集群都不能處理注冊實例請求以及讀取實例的請求。這樣保證的強一致性,但是可用性是打了折扣的。
如果以 Eureka 為注冊中心,注冊請求發到一個 Eureka 實例上之后,這個 Eureka 會轉發到集群內其他 Eureka 節點。
即使某些節點失敗,也不會將已經更新的回滾。並且無論集群內哪些 Eureka 掛了,也不會影響其他正常的 Eureka 繼續服務工作,雖然可能讀取到比較老的數據,以及有一些數據不一致。
目前的 CAP 理論
隨着技術的不斷發展以及理論的不斷完善,我們發現,分區並不是會經常出現的情況,大部分情況下,如果我們忽略 P ,其實就是可以實現 CA 共存的情況。如果分區是可以感知的,納悶我們可以提前制定響應策略,例如進入服務降級限制某些操作,通過恢復補償邏輯修正數據不一致。
在 CAP 基礎上演變的 PACELC 理論,就是針對這種情況的更為實際的指導意見。在出現分區的情況下,取前半部分,其實還是 CAP 理論。如果不出現分區的情況,也就是大部分的情況下,我們考慮 L(Latency,延遲) 與 C(Consistency 一致性)的權衡。
微信搜索“我的編程喵”關注公眾號,每日一刷,輕松提升技術,斬獲各種offer: