在分佈式系統領域,CAP定理可謂鼎鼎大名,各類理解和解釋頗多,今天,我也來聊聊本身的感覺。html
首先咱們先描述一下CAP定理的基本概念:算法
- 一致性(Consistency):每次請求均可以獲得最新的數據。
對於單機系統而言,這一點彷佛很容易保證,好比咱們更新的單機數據庫中的一條記錄以後不管怎麼讀取數據,都能獲得更新以後的最新數據【注1】。sql
可是對於一個有多個節點的分佈式系統,狀況就沒有這麼簡單了,通常狀況下節點之間的數據是經過「複製」的方式來同步的,假設你更新系統中某一節點的一條數據,對數據的更新操做會複製到系統的其餘節點,可是複製有一個「窗口期」,也就是說一個節點的更新複製到另外一個節點上須要必定的時間,在「窗口期」時間以內,請求到複製沒有完成的節點返回的數據就會產生不一致狀況。mongodb
理論上,咱們減少「窗口期」時間就能夠下降不一致發生的機率,可是「窗口期」永遠不可能爲零,及時節點「複製」達到了光速,即便使用了量子糾纏也不能讓複製行爲達到「同步」,因此完美的一致性在這個宇宙是不存在的只存在於神話中。數據庫
- 可用性(Availability):每次請求均可以獲得一個響應,可是獲得的數據不必定是最近的數據。
對於一個要持續可用的分佈式系統,每個非故障的節點必須對每個請求做出響應。也就是說,服務使用的任何算法都必須最終終止,當同時要求分區容忍性時,這是一個很強的定義:即便是嚴重的網絡錯誤,每一個請求必須終止。這裏須要注意發生故障且沒法響應客戶請求的節點,並不會致使失去這裏所述的「可用性」。網絡
可用性保證每次請求都能獲得響應,即便某些節點掛了,系統依然要響應請求。這點對於分佈式系統相當重要,咱們不能保證系統中衆多節點在運行期間總體可用,總會出現不可用的狀況,好比節點崩潰、節點數據異常、節點鏈接超時等,因此咱們要保證某些節點不可用的狀況下系統依然可用。架構
雖然咱們可用經過添加節點避免單點故障來提高整個系統的可用性,可是顯而易見的是咱們依然不能保證100%可用,咱們只能提高小數點後九的位數(99.999...%)。因此絕對的可用是沒法達到的,話說只要一說「絕對」好像都不靠譜。nosql
- 分區容錯性(Partition tolerance):當系統中有節點因網絡緣由沒法通訊時,系統依然能夠繼續運行。
分佈式系統由多個節點組成,節點間的網絡通訊老是不可靠的,全部咱們老是要保證分佈式系統節點間產生網絡分區的狀況下,這樣分佈式系統纔有存在的意義。分佈式
這裏須要注意的是,節點故障是否屬於網絡分區?這個問題確實容易讓人產生誤解。假設咱們有一個由三個節點組成的系統,其中一個節點down了,若是咱們認爲這種狀況下產生了網絡分區,那麼咱們只能在可用性和一致性作出選擇。可是咱們發現根據可用性定義,故障的節點並不影響可用性,並且故障節點已經不會相應任何請求了,其餘節點能夠很容易地進行補償(例如主備模式),彌補了可用性和一致性。因此若是節點故障屬於網絡分區,咱們就獲得一個違背CAP定理的結論——C、A、P咱們能夠同時保證。至此咱們從反面證實了網絡故障不屬於網絡分區。ide
可用性容易與分區容錯性相混淆,這兩個概念都是保證系統能夠持續對外提供服務。可是兩個概念側重點不一樣,可用性是保證系統中某些節點故障的狀況下系統可用,而分區容錯性是保證系統出現網絡分區即某些節點相互通訊失敗的狀況下,系統依然可用。
CAP定理定義了這三個屬性之間的相互關係:根據定理,分佈式系統只能知足三項中的兩項而不可能知足所有三項。這樣就產生三種取捨狀況:CA(withoutP)、CP(withoutA)、AP(withoutC)。
如今互聯網應用的場景中,系統節點衆多,節點之間網絡異常不可避免,因此要保證系統正常運行必須保證分區容錯性,那根據CAP定理,就要在可用性和一致性間作出選擇,從實際業務的角度上,這種選擇更像是一種權衡,就是說咱們更傾向於可用性多一些或者更傾向於一致性多一些。
傳統數據庫的分佈式事務大多采用這種模式,衆所周知XA事務最大的缺點就在於超時問題上,若是對一個資源管理器的事務提交操做由於網絡緣由等待,參與分佈式事務其餘節點都須要等待延時節點,導致系統變慢並最終致使不可用。
MySQL主從複製模式就是典型的AP應用場景,當主從節點產生網絡延時導致從節點數據不能及時同步時,咱們無需等待網絡恢復,依然能夠繼續訪問從節點獲取數據。
在當下互聯網業務場景中,咱們更多的時候是在可用性和一致性之間作出選擇。在實際的業務中,單純保證一致性不但沒法達到也會嚴重的影響系統的效率,同理可證,想要絕對的可用性也是不現實的,任何業務流程也不會容許大量的非一致性數據出現,這樣就形成了總體業務邏輯失敗。分佈式系統的可用性和一致性就如同太極陰陽兩面,你中有無,我中有你,做爲架構師咱們努力在業務場景尋找一致性和可用性的平衡點,對於架構師而言,「最」不重要,「合適」更好。
注1:單機系統依然會產生一致性問題,只是與CAP中一致性不是一個問題,故不在此展開。
注2:這裏還有一種狀況比較特殊,這種狀況是「CA」集羣,這種集羣極少發生網絡分區狀況,且一旦發生分區,就讓分區中的全部節點中止工做。這樣操做至關於捨棄了有問題節點,系統中其餘正常節點就不存在分區問題了。咱們並無在存在分區的系統中繼續工做,咱們很粗暴的解決了網絡分區的狀況。從某種意義上說,這是能夠實現的,可是實現起來很是麻煩,須要實時監控系統中節點是否出現網絡分區而且在一旦出現分區便可將分區內的節點所有下線。說到這裏你必定有一個疑惑,若是咱們將節點下線的難道不會影響CA中的可用性嗎?根據可用性定義可知,故障節點並不影響可用性,由於可用性須要保證非故障節點有響應。因此此處將分區節點下線以解決分區問題並不會影響可用性。
參考:
https://zh.wikipedia.org/wiki...
https://en.wikipedia.org/wiki...
http://www.runoob.com/mongodb...
http://www.hollischuang.com/a...
https://stackoverflow.com/que...
http://blog.nahurst.com/visua...
https://codahale.com/you-cant...
http://www.jdon.com/artichect...
http://www.jdon.com/46956《NoSQL精粹》