理論的優(yōu)點在于清晰簡潔藐守、易于理解,但缺點就是高度抽象化蹂风,省略了很多細節(jié)卢厂,導致在將理論應(yīng)用到實踐時,由于各種復雜情況硫眨,可能出現(xiàn)誤解和偏差,CAP 理論也不例外巢块。如果我們沒有意識到這些關(guān)鍵的細節(jié)點礁阁,那么在實踐中應(yīng)用 CAP 理論時,就可能發(fā)現(xiàn)方案很難落地族奢。
而且當談到數(shù)據(jù)一致性時姥闭,CAP、ACID越走、BASE 難免會被我們拿出來討論棚品,原因在于這三者都是和數(shù)據(jù)一致性相關(guān)的理論,如果不仔細理解三者之間的差別廊敌,則可能會陷入一頭霧水的狀態(tài)铜跑,不知道應(yīng)該用哪個才好。
CAP 的具體細節(jié)骡澈,簡單對比一下 ACID锅纺、BASE 幾個概念的關(guān)鍵區(qū)別點。
CAP 關(guān)鍵細節(jié)點
CAP 關(guān)注的粒度是數(shù)據(jù)肋殴,而不是整個系統(tǒng)囤锉。
C 與 A 之間的取舍可以在同一系統(tǒng)內(nèi)以非常細小的粒度反復發(fā)生,而每一次的決策可能因為具體的操作护锤,乃至因為牽涉到特定的數(shù)據(jù)或用戶而有所不同官地。
但這句話是理解和應(yīng)用 CAP 理論非常關(guān)鍵的一點。CAP 理論的定義和解釋中烙懦,用的都是 system驱入、node 這類系統(tǒng)級的概念,這就給很多人造成了很大的誤導,認為我們在進行架構(gòu)設(shè)計時沧侥,整個系統(tǒng)要么選擇 CP可霎,要么選擇 AP。但在實際設(shè)計過程中宴杀,每個系統(tǒng)不可能只處理一種數(shù)據(jù)癣朗,而是包含多種類型的數(shù)據(jù),有的數(shù)據(jù)必須選擇 CP旺罢,有的數(shù)據(jù)必須選擇 AP旷余。而如果我們做設(shè)計時,從整個系統(tǒng)的角度去選擇 CP 還是 AP扁达,就會發(fā)現(xiàn)顧此失彼正卧,無論怎么做都是有問題的。
以一個最簡單的用戶管理系統(tǒng)為例跪解,用戶管理系統(tǒng)包含用戶賬號數(shù)據(jù)(用戶 ID炉旷、密碼)、用戶信息數(shù)據(jù)(昵稱叉讥、興趣窘行、愛好、性別图仓、自我介紹等)罐盔。通常情況下,用戶賬號數(shù)據(jù)會選擇 CP救崔,而用戶信息數(shù)據(jù)會選擇 AP惶看,如果限定整個系統(tǒng)為 CP,則不符合用戶信息數(shù)據(jù)的應(yīng)用場景六孵;如果限定整個系統(tǒng)為 AP纬黎,則又不符合用戶賬號數(shù)據(jù)的應(yīng)用場景。
所以在 CAP 理論落地實踐時劫窒,我們需要將系統(tǒng)內(nèi)的數(shù)據(jù)按照不同的應(yīng)用場景和要求進行分類莹桅,每類數(shù)據(jù)選擇不同的策略(CP 還是 AP),而不是直接限定整個系統(tǒng)所有數(shù)據(jù)都是同一策略烛亦。
CAP 是忽略網(wǎng)絡(luò)延遲的诈泼。
這是一個非常隱含的假設(shè),布魯爾在定義一致性時煤禽,并沒有將延遲考慮進去铐达。也就是說,當事務(wù)提交時檬果,數(shù)據(jù)能夠瞬間復制到所有節(jié)點瓮孙。但實際情況下唐断,從節(jié)點 A 復制數(shù)據(jù)到節(jié)點 B,總是需要花費一定時間的杭抠。如果是相同機房脸甘,耗費時間可能是幾毫秒;如果是跨地域的機房偏灿,例如北京機房同步到廣州機房丹诀,耗費的時間就可能是幾十毫秒。這就意味著翁垂,CAP 理論中的 C 在實踐中是不可能完美實現(xiàn)的铆遭,在數(shù)據(jù)復制的過程中,節(jié)點 A 和節(jié)點 B 的數(shù)據(jù)并不一致沿猜。
不要小看了這幾毫秒或者幾十毫秒的不一致枚荣,對于某些嚴苛的業(yè)務(wù)場景,例如和金錢相關(guān)的用戶余額啼肩,或者和搶購相關(guān)的商品庫存橄妆,技術(shù)上是無法做到分布式場景下完美的一致性的。而業(yè)務(wù)上必須要求一致性祈坠,因此單個用戶的余額害碾、單個商品的庫存,理論上要求選擇 CP 而實際上 CP 都做不到颁虐,只能選擇 CA蛮原。也就是說卧须,只能單點寫入另绩,其他節(jié)點做備份,無法做到分布式情況下多點寫入花嘶。
需要注意的是笋籽,這并不意味著這類系統(tǒng)無法應(yīng)用分布式架構(gòu),只是說“單個用戶余額椭员、單個商品庫存”無法做分布式车海,但系統(tǒng)整體還是可以應(yīng)用分布式架構(gòu)的。例如隘击,下面的架構(gòu)圖是常見的將用戶分區(qū)的分布式架構(gòu)侍芝。
我們可以將用戶 id 為 0 ~ 100 的數(shù)據(jù)存儲在 Node 1,將用戶 id 為 101 ~ 200 的數(shù)據(jù)存儲在 Node 2埋同,Client 根據(jù)用戶 id 來決定訪問哪個 Node州叠。對于單個用戶來說,讀寫操作都只能在某個節(jié)點上進行凶赁;對所有用戶來說咧栗,有一部分用戶的讀寫操作在 Node 1 上逆甜,有一部分用戶的讀寫操作在 Node 2 上。
這樣的設(shè)計有一個很明顯的問題就是某個節(jié)點故障時致板,這個節(jié)點上的用戶就無法進行讀寫操作了交煞,但站在整體上來看,這種設(shè)計可以降低節(jié)點故障時受影響的用戶的數(shù)量和范圍斟或,畢竟只影響 20% 的用戶肯定要比影響所有用戶要好素征。這也是為什么挖掘機挖斷光纜后,支付寶只有一部分用戶會出現(xiàn)業(yè)務(wù)異常缕粹,而不是所有用戶業(yè)務(wù)異常的原因稚茅。
正常運行情況下,不存在 CP 和 AP 的選擇平斩,可以同時滿足 CA亚享。
CAP 理論告訴我們分布式系統(tǒng)只能選擇 CP 或者 AP,但其實這里的前提是系統(tǒng)發(fā)生了“分區(qū)”現(xiàn)象绘面。如果系統(tǒng)沒有發(fā)生分區(qū)現(xiàn)象欺税,也就是說 P 不存在的時候(節(jié)點間的網(wǎng)絡(luò)連接一切正常),我們沒有必要放棄 C 或者 A揭璃,應(yīng)該 C 和 A 都可以保證晚凿,這就要求架構(gòu)設(shè)計的時候既要考慮分區(qū)發(fā)生時選擇 CP 還是 AP,也要考慮分區(qū)沒有發(fā)生時如何保證 CA瘦馍。
同樣以用戶管理系統(tǒng)為例歼秽,即使是實現(xiàn) CA,不同的數(shù)據(jù)實現(xiàn)方式也可能不一樣:用戶賬號數(shù)據(jù)可以采用“消息隊列”的方式來實現(xiàn) CA情组,因為消息隊列可以比較好地控制實時性燥筷,但實現(xiàn)起來就復雜一些;而用戶信息數(shù)據(jù)可以采用“數(shù)據(jù)庫同步”的方式來實現(xiàn) CA院崇,因為數(shù)據(jù)庫的方式雖然在某些場景下可能延遲較高肆氓,但使用起來簡單。
放棄并不等于什么都不做底瓣,需要為分區(qū)恢復后做準備谢揪。
CAP 理論告訴我們?nèi)咧荒苋蓚€,需要“犧牲”(sacrificed)另外一個捐凭,這里的“犧牲”是有一定誤導作用的拨扶,因為“犧牲”讓很多人理解成什么都不做。實際上茁肠,CAP 理論的“犧牲”只是說在分區(qū)過程中我們無法保證 C 或者 A患民,但并不意味著什么都不做。因為在系統(tǒng)整個運行周期中官套,大部分時間都是正常的酒奶,發(fā)生分區(qū)現(xiàn)象的時間并不長蚁孔。例如,99.99% 可用性(俗稱 4 個 9)的系統(tǒng)惋嚎,一年運行下來杠氢,不可用的時間只有 50 分鐘;99.999%(俗稱 5 個 9)可用性的系統(tǒng)另伍,一年運行下來鼻百,不可用的時間只有 5 分鐘。分區(qū)期間放棄 C 或者 A摆尝,并不意味著永遠放棄 C 和 A温艇,我們可以在分區(qū)期間進行一些操作,從而讓分區(qū)故障解決后堕汞,系統(tǒng)能夠重新達到 CA 的狀態(tài)勺爱。
最典型的就是在分區(qū)期間記錄一些日志,當分區(qū)故障解決后讯检,系統(tǒng)根據(jù)日志進行數(shù)據(jù)恢復琐鲁,使得重新達到 CA 狀態(tài)。同樣以用戶管理系統(tǒng)為例人灼,對于用戶賬號數(shù)據(jù)围段,假設(shè)我們選擇了 CP,則分區(qū)發(fā)生后投放,節(jié)點 1 可以繼續(xù)注冊新用戶奈泪,節(jié)點 2 無法注冊新用戶(這里就是不符合 A 的原因,因為節(jié)點 2 收到注冊請求后會返回 error)灸芳,此時節(jié)點 1 可以將新注冊但未同步到節(jié)點 2 的用戶記錄到日志中涝桅。當分區(qū)恢復后,節(jié)點 1 讀取日志中的記錄耗绿,同步給節(jié)點 2苹支,當同步完成后砾隅,節(jié)點 1 和節(jié)點 2 就達到了同時滿足 CA 的狀態(tài)误阻。
而對于用戶信息數(shù)據(jù),假設(shè)我們選擇了 AP晴埂,則分區(qū)發(fā)生后究反,節(jié)點 1 和節(jié)點 2 都可以修改用戶信息,但兩邊可能修改不一樣儒洛。例如精耐,用戶在節(jié)點 1 中將愛好改為“旅游、美食琅锻、跑步”卦停,然后用戶在節(jié)點 2 中將愛好改為“美食向胡、游戲”,節(jié)點 1 和節(jié)點 2 都記錄了未同步的愛好數(shù)據(jù)惊完,當分區(qū)恢復后僵芹,系統(tǒng)按照某個規(guī)則來合并數(shù)據(jù)。例如小槐,按照“最后修改優(yōu)先規(guī)則”將用戶愛好修改為“美食拇派、游戲”,按照“字數(shù)最多優(yōu)先規(guī)則”則將用戶愛好修改為“旅游凿跳,美食件豌、跑步”,也可以完全將數(shù)據(jù)沖突報告出來控嗜,由人工來選擇具體應(yīng)該采用哪一條茧彤。
ACID
ACID 是數(shù)據(jù)庫管理系統(tǒng)為了保證事務(wù)的正確性而提出來的一個理論,ACID 包含四個約束疆栏,下面我來解釋一下棘街。
1.Atomicity(原子性)
一個事務(wù)中的所有操作,要么全部完成承边,要么全部不完成遭殉,不會在中間某個環(huán)節(jié)結(jié)束。事務(wù)在執(zhí)行過程中發(fā)生錯誤博助,會被回滾到事務(wù)開始前的狀態(tài)险污,就像這個事務(wù)從來沒有執(zhí)行過一樣。
2.Consistency(一致性)
在事務(wù)開始之前和事務(wù)結(jié)束以后富岳,數(shù)據(jù)庫的完整性沒有被破壞蛔糯。
3.Isolation(隔離性)
數(shù)據(jù)庫允許多個并發(fā)事務(wù)同時對數(shù)據(jù)進行讀寫和修改的能力。隔離性可以防止多個事務(wù)并發(fā)執(zhí)行時由于交叉執(zhí)行而導致數(shù)據(jù)的不一致窖式。事務(wù)隔離分為不同級別蚁飒,包括讀未提交(Read uncommitted)、讀提交(read committed)萝喘、可重復讀(repeatable read)和串行化(Serializable)淮逻。
4.Durability(持久性)
事務(wù)處理結(jié)束后,對數(shù)據(jù)的修改就是永久的阁簸,即便系統(tǒng)故障也不會丟失爬早。
可以看到,ACID 中的 A(Atomicity)和 CAP 中的 A(Availability)意義完全不同启妹,而 ACID 中的 C 和 CAP 中的 C 名稱雖然都是一致性筛严,但含義也完全不一樣。ACID 中的 C 是指數(shù)據(jù)庫的數(shù)據(jù)完整性饶米,而 CAP 中的 C 是指分布式節(jié)點中的數(shù)據(jù)一致性桨啃。再結(jié)合 ACID 的應(yīng)用場景是數(shù)據(jù)庫事務(wù)车胡,CAP 關(guān)注的是分布式系統(tǒng)數(shù)據(jù)讀寫這個差異點來看,其實 CAP 和 ACID 的對比就類似關(guān)公戰(zhàn)秦瓊照瘾,雖然關(guān)公和秦瓊都是武將吨拍,但其實沒有太多可比性。
BASE
BASE 是指基本可用(Basically Available)网杆、軟狀態(tài)( Soft State)羹饰、最終一致性( Eventual Consistency),核心思想是即使無法做到強一致性(CAP 的一致性就是強一致性)碳却,但應(yīng)用可以采用適合的方式達到最終一致性队秩。
1. 基本可用(Basically Available)
分布式系統(tǒng)在出現(xiàn)故障時,允許損失部分可用性昼浦,即保證核心可用馍资。
這里的關(guān)鍵詞是“部分”和“核心”,具體選擇哪些作為可以損失的業(yè)務(wù)关噪,哪些是必須保證的業(yè)務(wù)鸟蟹,是一項有挑戰(zhàn)的工作。例如使兔,對于一個用戶管理系統(tǒng)來說建钥,“登錄”是核心功能,而“注冊”可以算作非核心功能虐沥。因為未注冊的用戶本來就還沒有使用系統(tǒng)的業(yè)務(wù)熊经,注冊不了最多就是流失一部分用戶,而且這部分用戶數(shù)量較少欲险。如果用戶已經(jīng)注冊但無法登錄镐依,那就意味用戶無法使用系統(tǒng)。例如天试,充了錢的游戲不能玩了槐壳、云存儲不能用了……這些會對用戶造成較大損失,而且登錄用戶數(shù)量遠遠大于新注冊用戶喜每,影響范圍更大务唐。
2. 軟狀態(tài)(Soft State)
允許系統(tǒng)存在中間狀態(tài),而該中間狀態(tài)不會影響系統(tǒng)整體可用性灼卢。這里的中間狀態(tài)就是 CAP 理論中的數(shù)據(jù)不一致绍哎。
3. 最終一致性(Eventual Consistency)
系統(tǒng)中的所有數(shù)據(jù)副本經(jīng)過一定時間后来农,最終能夠達到一致的狀態(tài)鞋真。
這里的關(guān)鍵詞是“一定時間” 和 “最終”,“一定時間”和數(shù)據(jù)的特性是強關(guān)聯(lián)的沃于,不同的數(shù)據(jù)能夠容忍的不一致時間是不同的涩咖。舉一個微博系統(tǒng)的例子海诲,用戶賬號數(shù)據(jù)最好能在 1 分鐘內(nèi)就達到一致狀態(tài),因為用戶在 A 節(jié)點注冊或者登錄后檩互,1 分鐘內(nèi)不太可能立刻切換到另外一個節(jié)點特幔,但 10 分鐘后可能就重新登錄到另外一個節(jié)點了;而用戶發(fā)布的最新微博闸昨,可以容忍 30 分鐘內(nèi)達到一致狀態(tài)蚯斯,因為對于用戶來說,看不到某個明星發(fā)布的最新微博饵较,用戶是無感知的拍嵌,會認為明星沒有發(fā)布微博⊙撸“最終”的含義就是不管多長時間横辆,最終還是要達到一致性的狀態(tài)。
BASE 理論本質(zhì)上是對 CAP 的延伸和補充茄猫,更具體地說狈蚤,是對 CAP 中 AP 方案的一個補充。前面在剖析 CAP 理論時划纽,提到了其實和 BASE 相關(guān)的兩點:
CAP 理論是忽略延時的脆侮,而實際應(yīng)用中延時是無法避免的。
這一點就意味著完美的 CP 場景是不存在的勇劣,即使是幾毫秒的數(shù)據(jù)復制延遲他嚷,在這幾毫秒時間間隔內(nèi),系統(tǒng)是不符合 CP 要求的芭毙。因此 CAP 中的 CP 方案筋蓖,實際上也是實現(xiàn)了最終一致性,只是“一定時間”是指幾毫秒而已退敦。
AP 方案中犧牲一致性只是指分區(qū)期間粘咖,而不是永遠放棄一致性。
這一點其實就是 BASE 理論延伸的地方侈百,分區(qū)期間犧牲一致性瓮下,但分區(qū)故障恢復后,系統(tǒng)應(yīng)該達到最終一致性钝域。
綜合上面的分析讽坏,ACID 是數(shù)據(jù)庫事務(wù)完整性的理論,CAP 是分布式系統(tǒng)設(shè)計理論例证,BASE 是 CAP 理論中 AP 方案的延伸路呜。
小結(jié)
假如你來設(shè)計電商網(wǎng)站的高可用系統(tǒng),按照 CAP 理論的要求,你會如何設(shè)計胀葱?
評論1
一個電商網(wǎng)站核心模塊有會員漠秋,訂單,商品抵屿,支付庆锦,促銷管理等。
會員模塊轧葛,包括登錄搂抒,個人設(shè)置,個人訂單尿扯,購物車燕耿,收藏夾等,這些模塊保證AP姜胖,數(shù)據(jù)短時間不一致不影響使用誉帅。
訂單模塊的下單付款扣減庫存操作是整個系統(tǒng)的核心,我覺得CA都需要保證右莱,在極端情況下犧牲P是可以的蚜锨。
商品模塊的商品上下架和庫存管理保證CP,搜索功能因為本身就不是實時性非常高的模塊,所以保證AP就可以了慢蜓。
促銷是短時間的數(shù)據(jù)不一致亚再,結(jié)果就是優(yōu)惠信息看不到,但是已有的優(yōu)惠要保證可用晨抡,而且優(yōu)惠可以提前預計算氛悬,所以可以保證AP
現(xiàn)在大部分的電商網(wǎng)站對于支付這一塊是獨立的系統(tǒng),或者使用第三方的支付寶耘柱,微信如捅。其實CAP是由第三方來保證的,支付系統(tǒng)是一個對CAP要求極高的系統(tǒng)调煎,C是必須要保證的镜遣,AP中A相對更重要,不能因為分區(qū)士袄,導致所有人都不能支付