ACID中C與CAP定理中C的區別

banq發表於2015-01-02

ACIDCAP定理中都有C,代表Consistent一致性,很多人容易將這兩個C混為一談,其實這兩個一致性是有區別的。

事務的定義是一系列操作要麼全部成功,要麼全部不成功,資料庫的事務機制是通過ACID實現的,資料庫ACID的具體定義見這裡,ACID中的一致性的定義是:一個事務可以封裝狀態改變(除非它是一個只讀的)。事務必須始終保持系統處於一致的狀態,不管在任何給定的時間併發事務有多少。

也就是說:如果事務是併發多個,系統也必須如同序列事務一樣操作。其主要特徵是保護性和不變性(Preserving an Invariant),以轉賬案例為例,假設有五個賬戶,每個賬戶餘額是100元,那麼五個賬戶總額是500元,如果在這個5個賬戶之間同時發生多個轉賬,無論併發多少個,比如在A與B賬戶之間轉賬5元,在C與D賬戶之間轉賬10元,在B與E之間轉賬15元,五個賬戶總額也應該還是500元,這就是保護性和不變性。

如果說ACID的C是節點伺服器的資料完整性,而CAP的一致性是分散式多伺服器之間複製資料以取得這些伺服器擁有同樣的資料,這是一種分散式領域的一致性概念。因此兩者是完全不同的概念。

分散式領域中的一致性有的強弱之分,強一致性也就是指一旦有寫操作寫入任何一個伺服器,立即在其他伺服器之間同步複製新的資料,這樣, 任何伺服器上任何讀操作總是能看到最近寫入的新資料。如果不能立即看到最近寫入的新資料,而可能過了一段時間才能看到,則屬於弱一致性或最終一致性了。

強一致性分為由寫實現一致性Consistency by writes、由讀實現一致性Consistency by reads和由衝裁實現一致性Consistency by Quorum。

由寫實現一致性:在寫入資料同時,將資料複製到其他伺服器上,讀取任何一臺都可以獲得新的寫入資料,複製資料是在寫操作完成,讀操作輕量。

由讀實現一致性:寫入一旦伺服器後,不再複製,而是在讀取時使用版本來協調複製(如vector clock演算法),這樣我們簡化了寫操作,而將負擔加在讀操作。

由衝裁實現一致性:如果寫入時複製到其他2/3大多數伺服器,讀取時也是從2/3大多數伺服器讀取,讀取這邊負責解決哪個更新是最新結果,這在讀操作和寫操作之間分擔了負載。

回到事務話題,如果要在分散式系統中實現像ACID那樣的事務機制,只有強一致性還是不夠的,如果我們操作步驟順序很重要,不可以中斷或打亂,我們要麼一起一次執行它們,如果併發執行這些操作步驟,無論怎麼併發,也要如同它們是在獨立執行,我們最終得到的結果總是相同的,這是一種更強的一致性:線性一致性linearizable consistency,類似ACID中的隔離層(serial isolation level)。

The CAP FAQ將CAP定理中的一致性定義為這種線性一致性或稱為atomic原子一致性。一種比普通一致性更強的一致性,這也是大家又將ACID的C和CAP的C等同在一起的原因。ACID的C與CAP的C的關係類似精確與一致性的關係,如下圖:


ACID中C與CAP定理中C的區別

這種分散式的線性強一致性有兩種實現方式:2PC兩段提交和Paxos演算法是常見兩種。

通過2PC寫入新資料需要經過兩次來回,第一次請求commit,第二次才正式確認commit,在這兩者之間過程中,所有伺服器都會堵塞等待發起者發出整個事務成功還是失敗的結果(只有發起者知道所有伺服器的情況),如果失敗,所有伺服器返回之前狀態,相當於寫入資料失敗,寫入資料沒有發生過一樣。

而Paxos演算法能夠迴避2PC的堵塞死鎖等問題更好地實現伺服器之間資料強一致複製,具體內容見:Paxos演算法。也可參考比Paxos演算法改進的Raft演算法

參考:

Lightweight transactions in Cassandra 2.0

Distributed algorithms and protocols:Consistency

The Consistency Alphabet Soup

[該貼被banq於2015-01-02 20:00修改過]

相關文章