定義
在一個分布式系統(指系統中的節點互相連接並共享數據)中,當涉及讀寫操作時,只能保證一致性 (Consistency)、可用性 (Availability)、分區容錯性 (Partition Tolerance)三者中的兩個,另外一個必須被犧牲。
- 一致性:CAP中的C和ACID 中的C不是一個含義,ACID 中的C是指數據庫中的數據滿足一定的約束條件。而CAP中的C是指線性一致性,即:客戶端向系統寫入什么,那么讀出來的也會是什么。也就是要保證客戶端讀取到的數據一定是上次寫入的最新數據。
- 可用性:指系統中的部分節點出現故障后,系統能否還能對外提供完全可用的服務;
- 分區容錯性:指是否允許系統中的節點之間無法通信,也就是無法互相連接;
適用場景
那么什么樣的分布式系統是節點之間互聯並共享數據呢?
典型的場景就是數據庫的主從集群,一個數據庫集群有一個主,多個從,主從之間會進行數據復制。所以適用於CAP原理。
那么如果我現在是一個Redis的集群,集群中每台機器存儲不同的數據,集群中每台機器不需要復制和傳遞數據,那么就不屬於CAP原理的討論范圍。同理,如果是A,B兩個不同的業務系統,比如招行賬號A給工行賬號B轉賬100元,由於招行和工行是兩個不同的業務系統,業務上隔離,且他們之間也沒有共享的數據,從而也不屬於CAP原理的討論范圍。
場景方案選擇
- 傳統數據庫主從集群:如果當前是一個現在是一個主從復制的數據庫集群,同一條數據會在主從數據庫上都存儲,那么當存在主從數據庫之間網絡斷開時,我們確實只能要么選擇A放棄C,要么選擇C放棄A。選擇A放棄C,就是客戶端讀取到的可能不是最新的數據,但是系統持續可用;選擇C放棄A,就是讓系統服務不可用,客戶端自然就不會認為數據不一致了。
- 分布式數據庫,如阿里的OceanBase,這種數據庫也是一個主從的集群,但是主從節點往往使用Paxos/Raft等副本一致性協議,做到整個數據庫系統,在部分節點發生故障時,也能在很短的時間內自動重新選主,選出一個新的主從集群的數據庫系統。在重新選主的過程中,系統不可用,相當於放棄了A,而一旦選出新的主之后,系統又繼續可用,且數據對外是線性一致的。相比傳統的數據庫主從集群,分布式數據庫由於可以在遇到網絡分區導致數據庫主從節點之間無法互聯時,可以快速選出新的主,然后快速恢復,所以架構設計上和用戶體驗上,要好很多。但是系統設計的復雜度也非常高。
分布式事務
通過上面的分析,我們知道CAP中的數據一致性,本質上是為了維護同一個數據的不同副本之間的一致性。而更多的時候,我們要解決的是不同業務系統之間的數據一致性,即數據之間總是應該滿足規定的業務規則。典型的場景比如有跨行轉賬、訂單和減庫存。這種場景,由於沒有數據共享的特征,所以不適用於CAP。比如A銀行的賬戶給B銀行的賬戶轉賬100元,那么轉賬前后,兩個賬戶的錢加起來應該不變。也就是A扣款了,B就必須加款。那么這種場景如何解決呢?一般的做法是采用分布式事務,常見的分布式事務的解決方案有:2PC\3PC、TCC、基於分布式MQ+本地消息、分布式MQ事務消息、Sagas。