在前面三篇文章中,介紹了關(guān)于分布式系統(tǒng)中數(shù)據(jù)一致性的問題,這一篇主要介紹CAP定理以及自己對CAP定理的了解。
CAP定理是2000年,由 Eric Brewer 提出來的
Brewer認為在分布式的環(huán)境下設(shè)計和部署系統(tǒng)時,有3個核心的需求,以一種特殊的關(guān)系存在。這里的分布式系統(tǒng)說的是在物理上分布的系統(tǒng),比如我們常見的web系統(tǒng)。
這3個核心的需求是:Consistency,Availability和Partition Tolerance,賦予了該理論另外一個名字 - CAP。
Consistency:一致性,這個和數(shù)據(jù)庫ACID的一致性類似,但這里關(guān)注的所有數(shù)據(jù)節(jié)點上的數(shù)據(jù)一致性和正確性,而數(shù)據(jù)庫的ACID關(guān)注的是在在一個事務(wù)內(nèi),對數(shù)據(jù)的一些約束。
Availability:可用性,關(guān)注的在某個結(jié)點的數(shù)據(jù)是否可用,可以認為某一個節(jié)點的系統(tǒng)是否可用,通信故障除外。
Partition Tolerance:分區(qū)容忍性,是否可以對數(shù)據(jù)進行分區(qū)。這是考慮到性能和可伸縮性。
為什么不能完全保證這個三點了,個人覺得主要是因為一旦進行分區(qū)了,就說明了必須節(jié)點之間必須進行通信,涉及到通信,就無法確保在有限的時間內(nèi)完成指定的行文,如果要求兩個操作之間要完整的進行,因為涉及到通信,肯定存在某一個時刻只完成一部分的業(yè)務(wù)操作,在通信完成的這一段時間內(nèi),數(shù)據(jù)就是不一致性的。如果要求保證一致性,那么就必須在通信完成這一段時間內(nèi)保護數(shù)據(jù),使得任何訪問這些數(shù)據(jù)的操作不可用。
如果想保證一致性和可用性,那么數(shù)據(jù)就不能夠分區(qū)。一個簡單的理解就是所有的數(shù)據(jù)就必須存放在一個數(shù)據(jù)庫里面,不能進行數(shù)據(jù)庫拆分。這個對于大數(shù)據(jù)量,高并發(fā)的互聯(lián)網(wǎng)應(yīng)用來說,是不可接受的。
我們可以拿一個簡單的例子來說明:假設(shè)一個購物系統(tǒng),賣家A和賣家B做了一筆交易100元,交易成功了,買家把錢給賣家。
這里面存在兩張表的數(shù)據(jù):Trade表Account表 ,涉及到三條數(shù)據(jù)Trade(100),Account A ,Account B
假設(shè) trade表和account表在一個數(shù)據(jù)庫,那么只需要使用數(shù)據(jù)庫的事務(wù),就可以保證一致性,同時不會影響可用性。但是隨著交易量越來越大,我們可以考慮按照業(yè)務(wù)分庫,把交易庫和account庫單獨分開,這樣就涉及到trade庫和account庫進行通信,也就是存在了分區(qū),那么我們就不可能同時保證可用性和一致性。
我們假設(shè)初始狀態(tài)
trade(buyer,seller,tradeNo,status) = trade(A,B,20121001,I)
account(accountNo,balance) = account(A,300)
account(accountNo,balance) = account(B,10)
在理想情況下,我們期望的狀態(tài)是
trade(buyer,seller,tradeNo,status) = trade(A,B,20121001,S)
account(accountNo,balance) = account(A,200)
account(accountNo,balance) = account(B,110)
但是考慮到一些異常情況
假設(shè)在trade(20121001,S)更新完成之前,帳戶A進行扣款之后,帳戶A進行了另外一筆300款錢的交易,把錢消費了,那么就存在一個狀態(tài)
trade(buyer,seller,tradeNo,status) = trade(A,B,20121001,S)
account(accountNo,balance) = account(A,0)
account(accountNo,balance) = account(B,10)
產(chǎn)生了數(shù)據(jù)不一致的狀態(tài)
由于這個涉及到資金上的問題,對資金要求比較高,我們必須保證一致性,那么怎么辦,只能在進行trade(A,B,20121001)交易的時候,對于任何A的后續(xù)交易請求trade(A,X,X),必須等到A完成之后,才能夠進行處理,也就是說在進行trade(A,B,20121001)的時候,Account(A)的數(shù)據(jù)是不可用的。
任何架構(gòu)師在設(shè)計分布式的系統(tǒng)的時候,都必須在這三者之間進行取舍。首先就是是否選擇分區(qū),由于在一個數(shù)據(jù)分區(qū)內(nèi),根據(jù)數(shù)據(jù)庫的ACID特性,是可以保證一致性的,不會存在可用性和一致性的問題,唯一需要考慮的就是性能問題。對于可用性和一致性,大多數(shù)應(yīng)用就必須保證可用性,畢竟是互聯(lián)網(wǎng)應(yīng)用,犧牲了可用性,相當于間接的影響了用戶體驗,而唯一可以考慮就是一致性了。
犧牲一致性
對于犧牲一致性的情況最多的就是緩存和數(shù)據(jù)庫的數(shù)據(jù)同步問題,我們把緩存看做一個數(shù)據(jù)分區(qū)節(jié)點,數(shù)據(jù)庫看作另外一個節(jié)點,這兩個節(jié)點之間的數(shù)據(jù)在任何時刻都無法保證一致性的。在web2.0這樣的業(yè)務(wù),開心網(wǎng)來舉例子,訪問一個用戶的信息的時候,可以先訪問緩存的數(shù)據(jù),但是如果用戶修改了自己的一些信息,首先修改的是數(shù)據(jù)庫,然后在通知緩存進行更新,這段期間內(nèi)就會導(dǎo)致的數(shù)據(jù)不一致,用戶可能訪問的是一個過期的緩存,而不是最新的數(shù)據(jù)。但是由于這些業(yè)務(wù)對一致性的要求比較高,不會帶來太大的影響。
異常錯誤檢測和補償
還有一種犧牲一致性的方法就是通過一種錯誤補償機制來進行,可以拿上面購物的例子來說,假設(shè)我們把業(yè)務(wù)邏輯順序調(diào)整一下,先扣買家錢,然后更新交易狀態(tài),在把錢打給賣家
我們假設(shè)初始狀態(tài)
account(accountNo,balance) = account(A,300)
account(accountNo,balance) = account(B,10)
trade(buyer,seller,tradeNo,status) = trade(A,B,20121001,I)
那么有可能出現(xiàn)
account(accountNo,balance) = account(A,200)
trade(buyer,seller,tradeNo,status) = trade(A,B,20121001,S)
account(accountNo,balance) = account(B,10)
那么就出現(xiàn)了A扣款成功,交易狀態(tài)也成功了,但是錢沒有打給B,這個時候可以通過一個時候的異?;謴?fù)機制,把錢打給B,最終的情況保證了一致性,在一定時間內(nèi)數(shù)據(jù)可能是不一致的,但是不會影響太大。
兩階段提交協(xié)議
當然,還有一種方式就是我另外一篇文章里面《X/Open DTP-分布式事務(wù)模型》里面說的,但是再第一階段和第二階段之間,數(shù)據(jù)也可不能是一致性的,也可能出現(xiàn)同樣的情況導(dǎo)致異常。而且DTP的分布式事務(wù)模型 限制太多,例如必須有實現(xiàn)其功能的相關(guān)的容器支持,并且資源管理器也必須實現(xiàn)了XA規(guī)范。限制比較多。
國外有的架構(gòu)師有兩種方案去解決CAP的限制,但是也是比較適合特定的業(yè)務(wù),而沒有通用的解決方案,
探知分區(qū)->分區(qū)內(nèi)操作->事后補償
就是上面介紹的異常檢測恢復(fù)機制,這種機制其實還是有限制,
首先對于分區(qū)檢測操作,不同的業(yè)務(wù)涉及到的分區(qū)操作可能不一樣
分區(qū)內(nèi)操作限制:不同的業(yè)務(wù)對應(yīng)的約束不一致
事后補償:由于業(yè)務(wù)約束不一樣,補償方式也不一樣。
所以這只能作為一種思想,不能做一個通用的解決方案
轉(zhuǎn)載自:http://www.cnblogs.com/aigongsi/archive/2012/10/15/2721366.html