理論的優(yōu)點(diǎn)在于清晰簡(jiǎn)潔首昔、易于理解寡喝,但缺點(diǎn)就是高度抽象化,省略了很多細(xì)節(jié)勒奇,導(dǎo)致在將理論應(yīng)用到實(shí)踐時(shí)拘荡,由于各種復(fù)雜情況,可能出現(xiàn)誤解和偏差撬陵,CAP 理論也不例外珊皿。如果我們沒(méi)有意識(shí)到這些關(guān)鍵的細(xì)節(jié)點(diǎn),那么在實(shí)踐中應(yīng)用 CAP 理論時(shí)巨税,就可能發(fā)現(xiàn)方案很難落地蟋定。
而且當(dāng)談到數(shù)據(jù)一致性時(shí),CAP草添、ACID驶兜、BASE 難免會(huì)被我們拿出來(lái)討論,原因在于這三者都是和數(shù)據(jù)一致性相關(guān)的理論远寸,如果不仔細(xì)理解三者之間的差別抄淑,則可能會(huì)陷入一頭霧水的狀態(tài),不知道應(yīng)該用哪個(gè)才好驰后。
今天肆资,我來(lái)講講CAP 的具體細(xì)節(jié),簡(jiǎn)單對(duì)比一下 ACID灶芝、BASE 幾個(gè)概念的關(guān)鍵區(qū)別點(diǎn)郑原。
CAP 關(guān)鍵細(xì)節(jié)點(diǎn)
埃里克·布魯爾(Eric Brewer)在《CAP 理論十二年回顧:“規(guī)則”變了》(http://www.infoq.com/cn/articles/cap-twelve-years-later-how-the-rules-have-changed)一文中詳細(xì)地闡述了理解和應(yīng)用 CAP 的一些細(xì)節(jié)點(diǎn),可能是由于作者寫(xiě)作風(fēng)格的原因夜涕,對(duì)于一些非常關(guān)鍵的細(xì)節(jié)點(diǎn)一句話就帶過(guò)了,這里我特別提煉出來(lái)重點(diǎn)闡述。
CAP 關(guān)注的粒度是數(shù)據(jù)愉适,而不是整個(gè)系統(tǒng)浸遗。
原文就只有一句話:
C 與 A 之間的取舍可以在同一系統(tǒng)內(nèi)以非常細(xì)小的粒度反復(fù)發(fā)生,而每一次的決策可能因?yàn)榫唧w的操作驾胆,乃至因?yàn)闋可娴教囟ǖ臄?shù)據(jù)或用戶(hù)而有所不同涣澡。
但這句話是理解和應(yīng)用 CAP 理論非常關(guān)鍵的一點(diǎn)。CAP 理論的定義和解釋中俏拱,用的都是 system暑塑、node 這類(lèi)系統(tǒng)級(jí)的概念,這就給很多人造成了很大的誤導(dǎo)锅必,認(rèn)為我們?cè)谶M(jìn)行架構(gòu)設(shè)計(jì)時(shí)事格,整個(gè)系統(tǒng)要么選擇 CP,要么選擇 AP搞隐。但在實(shí)際設(shè)計(jì)過(guò)程中驹愚,每個(gè)系統(tǒng)不可能只處理一種數(shù)據(jù),而是包含多種類(lèi)型的數(shù)據(jù)劣纲,有的數(shù)據(jù)必須選擇 CP逢捺,有的數(shù)據(jù)必須選擇 AP。而如果我們做設(shè)計(jì)時(shí)癞季,從整個(gè)系統(tǒng)的角度去選擇 CP 還是 AP劫瞳,就會(huì)發(fā)現(xiàn)顧此失彼倘潜,無(wú)論怎么做都是有問(wèn)題的。
以一個(gè)最簡(jiǎn)單的用戶(hù)管理系統(tǒng)為例志于,用戶(hù)管理系統(tǒng)包含用戶(hù)賬號(hào)數(shù)據(jù)(用戶(hù) ID涮因、密碼)、用戶(hù)信息數(shù)據(jù)(昵稱(chēng)伺绽、興趣养泡、愛(ài)好、性別奈应、自我介紹等)澜掩。通常情況下,用戶(hù)賬號(hào)數(shù)據(jù)會(huì)選擇 CP杖挣,而用戶(hù)信息數(shù)據(jù)會(huì)選擇 AP肩榕,如果限定整個(gè)系統(tǒng)為 CP,則不符合用戶(hù)信息數(shù)據(jù)的應(yīng)用場(chǎng)景程梦;如果限定整個(gè)系統(tǒng)為 AP点把,則又不符合用戶(hù)賬號(hào)數(shù)據(jù)的應(yīng)用場(chǎng)景。
所以在 CAP 理論落地實(shí)踐時(shí)屿附,我們需要將系統(tǒng)內(nèi)的數(shù)據(jù)按照不同的應(yīng)用場(chǎng)景和要求進(jìn)行分類(lèi)郎逃,每類(lèi)數(shù)據(jù)選擇不同的策略(CP 還是 AP),而不是直接限定整個(gè)系統(tǒng)所有數(shù)據(jù)都是同一策略挺份。
CAP 是忽略網(wǎng)絡(luò)延遲的褒翰。
這是一個(gè)非常隱含的假設(shè),布魯爾在定義一致性時(shí)匀泊,并沒(méi)有將延遲考慮進(jìn)去优训。也就是說(shuō),當(dāng)事務(wù)提交時(shí)各聘,數(shù)據(jù)能夠瞬間復(fù)制到所有節(jié)點(diǎn)揣非。但實(shí)際情況下,從節(jié)點(diǎn) A 復(fù)制數(shù)據(jù)到節(jié)點(diǎn) B躲因,總是需要花費(fèi)一定時(shí)間的早敬。如果是相同機(jī)房,耗費(fèi)時(shí)間可能是幾毫秒大脉;如果是跨地域的機(jī)房搞监,例如北京機(jī)房同步到廣州機(jī)房,耗費(fèi)的時(shí)間就可能是幾十毫秒镰矿。這就意味著琐驴,CAP 理論中的 C 在實(shí)踐中是不可能完美實(shí)現(xiàn)的,在數(shù)據(jù)復(fù)制的過(guò)程中,節(jié)點(diǎn) A 和節(jié)點(diǎn) B 的數(shù)據(jù)并不一致绝淡。
不要小看了這幾毫秒或者幾十毫秒的不一致宙刘,對(duì)于某些嚴(yán)苛的業(yè)務(wù)場(chǎng)景,例如和金錢(qián)相關(guān)的用戶(hù)余額牢酵,或者和搶購(gòu)相關(guān)的商品庫(kù)存荐类,技術(shù)上是無(wú)法做到分布式場(chǎng)景下完美的一致性的。而業(yè)務(wù)上必須要求一致性茁帽,因此單個(gè)用戶(hù)的余額、單個(gè)商品的庫(kù)存屈嗤,理論上要求選擇 CP 而實(shí)際上 CP 都做不到潘拨,只能選擇 CA。也就是說(shuō)饶号,只能單點(diǎn)寫(xiě)入铁追,其他節(jié)點(diǎn)做備份,無(wú)法做到分布式情況下多點(diǎn)寫(xiě)入茫船。
需要注意的是琅束,這并不意味著這類(lèi)系統(tǒng)無(wú)法應(yīng)用分布式架構(gòu),只是說(shuō)“單個(gè)用戶(hù)余額算谈、單個(gè)商品庫(kù)存”無(wú)法做分布式涩禀,但系統(tǒng)整體還是可以應(yīng)用分布式架構(gòu)的。例如然眼,下面的架構(gòu)圖是常見(jiàn)的將用戶(hù)分區(qū)的分布式架構(gòu)艾船。
我們可以將用戶(hù) id 為 0 ~ 100 的數(shù)據(jù)存儲(chǔ)在 Node 1,將用戶(hù) id 為 101 ~ 200 的數(shù)據(jù)存儲(chǔ)在 Node 2高每,Client 根據(jù)用戶(hù) id 來(lái)決定訪問(wèn)哪個(gè) Node屿岂。對(duì)于單個(gè)用戶(hù)來(lái)說(shuō),讀寫(xiě)操作都只能在某個(gè)節(jié)點(diǎn)上進(jìn)行鲸匿;對(duì)所有用戶(hù)來(lái)說(shuō)爷怀,有一部分用戶(hù)的讀寫(xiě)操作在 Node 1 上,有一部分用戶(hù)的讀寫(xiě)操作在 Node 2 上带欢。
這樣的設(shè)計(jì)有一個(gè)很明顯的問(wèn)題就是某個(gè)節(jié)點(diǎn)故障時(shí)运授,這個(gè)節(jié)點(diǎn)上的用戶(hù)就無(wú)法進(jìn)行讀寫(xiě)操作了,但站在整體上來(lái)看洪囤,這種設(shè)計(jì)可以降低節(jié)點(diǎn)故障時(shí)受影響的用戶(hù)的數(shù)量和范圍徒坡,畢竟只影響 20% 的用戶(hù)肯定要比影響所有用戶(hù)要好。這也是為什么挖掘機(jī)挖斷光纜后瘤缩,支付寶只有一部分用戶(hù)會(huì)出現(xiàn)業(yè)務(wù)異常喇完,而不是所有用戶(hù)業(yè)務(wù)異常的原因。
正常運(yùn)行情況下剥啤,不存在 CP 和 AP 的選擇锦溪,可以同時(shí)滿足 CA不脯。
CAP 理論告訴我們分布式系統(tǒng)只能選擇 CP 或者 AP,但其實(shí)這里的前提是系統(tǒng)發(fā)生了“分區(qū)”現(xiàn)象刻诊。如果系統(tǒng)沒(méi)有發(fā)生分區(qū)現(xiàn)象防楷,也就是說(shuō) P 不存在的時(shí)候(節(jié)點(diǎn)間的網(wǎng)絡(luò)連接一切正常),我們沒(méi)有必要放棄 C 或者 A则涯,應(yīng)該 C 和 A 都可以保證复局,這就要求架構(gòu)設(shè)計(jì)的時(shí)候既要考慮分區(qū)發(fā)生時(shí)選擇 CP 還是 AP,也要考慮分區(qū)沒(méi)有發(fā)生時(shí)如何保證 CA粟判。
同樣以用戶(hù)管理系統(tǒng)為例亿昏,即使是實(shí)現(xiàn) CA,不同的數(shù)據(jù)實(shí)現(xiàn)方式也可能不一樣:用戶(hù)賬號(hào)數(shù)據(jù)可以采用“消息隊(duì)列”的方式來(lái)實(shí)現(xiàn) CA档礁,因?yàn)橄㈥?duì)列可以比較好地控制實(shí)時(shí)性角钩,但實(shí)現(xiàn)起來(lái)就復(fù)雜一些;而用戶(hù)信息數(shù)據(jù)可以采用“數(shù)據(jù)庫(kù)同步”的方式來(lái)實(shí)現(xiàn) CA呻澜,因?yàn)閿?shù)據(jù)庫(kù)的方式雖然在某些場(chǎng)景下可能延遲較高递礼,但使用起來(lái)簡(jiǎn)單。
放棄并不等于什么都不做羹幸,需要為分區(qū)恢復(fù)后做準(zhǔn)備脊髓。
CAP 理論告訴我們?nèi)咧荒苋蓚€(gè),需要“犧牲”(sacrificed)另外一個(gè)睹欲,這里的“犧牲”是有一定誤導(dǎo)作用的供炼,因?yàn)椤盃奚弊尯芏嗳死斫獬墒裁炊疾蛔觥?shí)際上窘疮,CAP 理論的“犧牲”只是說(shuō)在分區(qū)過(guò)程中我們無(wú)法保證 C 或者 A袋哼,但并不意味著什么都不做。因?yàn)樵谙到y(tǒng)整個(gè)運(yùn)行周期中闸衫,大部分時(shí)間都是正常的涛贯,發(fā)生分區(qū)現(xiàn)象的時(shí)間并不長(zhǎng)。例如蔚出,99.99% 可用性(俗稱(chēng) 4 個(gè) 9)的系統(tǒng)弟翘,一年運(yùn)行下來(lái),不可用的時(shí)間只有 50 分鐘骄酗;99.999%(俗稱(chēng) 5 個(gè) 9)可用性的系統(tǒng)稀余,一年運(yùn)行下來(lái),不可用的時(shí)間只有 5 分鐘趋翻。分區(qū)期間放棄 C 或者 A睛琳,并不意味著永遠(yuǎn)放棄 C 和 A,我們可以在分區(qū)期間進(jìn)行一些操作,從而讓分區(qū)故障解決后师骗,系統(tǒng)能夠重新達(dá)到 CA 的狀態(tài)历等。
最典型的就是在分區(qū)期間記錄一些日志,當(dāng)分區(qū)故障解決后辟癌,系統(tǒng)根據(jù)日志進(jìn)行數(shù)據(jù)恢復(fù)寒屯,使得重新達(dá)到 CA 狀態(tài)。同樣以用戶(hù)管理系統(tǒng)為例黍少,對(duì)于用戶(hù)賬號(hào)數(shù)據(jù)寡夹,假設(shè)我們選擇了 CP,則分區(qū)發(fā)生后厂置,節(jié)點(diǎn) 1 可以繼續(xù)注冊(cè)新用戶(hù)要出,節(jié)點(diǎn) 2 無(wú)法注冊(cè)新用戶(hù)(這里就是不符合 A 的原因,因?yàn)楣?jié)點(diǎn) 2 收到注冊(cè)請(qǐng)求后會(huì)返回 error)农渊,此時(shí)節(jié)點(diǎn) 1 可以將新注冊(cè)但未同步到節(jié)點(diǎn) 2 的用戶(hù)記錄到日志中。當(dāng)分區(qū)恢復(fù)后或颊,節(jié)點(diǎn) 1 讀取日志中的記錄砸紊,同步給節(jié)點(diǎn) 2,當(dāng)同步完成后囱挑,節(jié)點(diǎn) 1 和節(jié)點(diǎn) 2 就達(dá)到了同時(shí)滿足 CA 的狀態(tài)醉顽。
而對(duì)于用戶(hù)信息數(shù)據(jù),假設(shè)我們選擇了 AP平挑,則分區(qū)發(fā)生后游添,節(jié)點(diǎn) 1 和節(jié)點(diǎn) 2 都可以修改用戶(hù)信息,但兩邊可能修改不一樣通熄。例如唆涝,用戶(hù)在節(jié)點(diǎn) 1 中將愛(ài)好改為“旅游、美食唇辨、跑步”廊酣,然后用戶(hù)在節(jié)點(diǎn) 2 中將愛(ài)好改為“美食、游戲”赏枚,節(jié)點(diǎn) 1 和節(jié)點(diǎn) 2 都記錄了未同步的愛(ài)好數(shù)據(jù)亡驰,當(dāng)分區(qū)恢復(fù)后,系統(tǒng)按照某個(gè)規(guī)則來(lái)合并數(shù)據(jù)饿幅。例如凡辱,按照“最后修改優(yōu)先規(guī)則”將用戶(hù)愛(ài)好修改為“美食、游戲”栗恩,按照“字?jǐn)?shù)最多優(yōu)先規(guī)則”則將用戶(hù)愛(ài)好修改為“旅游透乾,美食、跑步”,也可以完全將數(shù)據(jù)沖突報(bào)告出來(lái)续徽,由人工來(lái)選擇具體應(yīng)該采用哪一條蚓曼。
ACID
ACID 是數(shù)據(jù)庫(kù)管理系統(tǒng)為了保證事務(wù)的正確性而提出來(lái)的一個(gè)理論,ACID 包含四個(gè)約束钦扭,下面我來(lái)解釋一下纫版。
1.Atomicity(原子性)
一個(gè)事務(wù)中的所有操作,要么全部完成客情,要么全部不完成其弊,不會(huì)在中間某個(gè)環(huán)節(jié)結(jié)束。事務(wù)在執(zhí)行過(guò)程中發(fā)生錯(cuò)誤膀斋,會(huì)被回滾到事務(wù)開(kāi)始前的狀態(tài)梭伐,就像這個(gè)事務(wù)從來(lái)沒(méi)有執(zhí)行過(guò)一樣。
2.Consistency(一致性)
在事務(wù)開(kāi)始之前和事務(wù)結(jié)束以后仰担,數(shù)據(jù)庫(kù)的完整性沒(méi)有被破壞糊识。
3.Isolation(隔離性)
數(shù)據(jù)庫(kù)允許多個(gè)并發(fā)事務(wù)同時(shí)對(duì)數(shù)據(jù)進(jìn)行讀寫(xiě)和修改的能力。隔離性可以防止多個(gè)事務(wù)并發(fā)執(zhí)行時(shí)由于交叉執(zhí)行而導(dǎo)致數(shù)據(jù)的不一致摔蓝。事務(wù)隔離分為不同級(jí)別赂苗,包括讀未提交(Read uncommitted)、讀提交(read committed)贮尉、可重復(fù)讀(repeatable read)和串行化(Serializable)拌滋。
4.Durability(持久性)
事務(wù)處理結(jié)束后,對(duì)數(shù)據(jù)的修改就是永久的猜谚,即便系統(tǒng)故障也不會(huì)丟失败砂。
可以看到,ACID 中的 A(Atomicity)和 CAP 中的 A(Availability)意義完全不同魏铅,而 ACID 中的 C 和 CAP 中的 C 名稱(chēng)雖然都是一致性昌犹,但含義也完全不一樣。ACID 中的 C 是指數(shù)據(jù)庫(kù)的數(shù)據(jù)完整性览芳,而 CAP 中的 C 是指分布式節(jié)點(diǎn)中的數(shù)據(jù)一致性祭隔。再結(jié)合 ACID 的應(yīng)用場(chǎng)景是數(shù)據(jù)庫(kù)事務(wù),CAP 關(guān)注的是分布式系統(tǒng)數(shù)據(jù)讀寫(xiě)這個(gè)差異點(diǎn)來(lái)看路操,其實(shí) CAP 和 ACID 的對(duì)比就類(lèi)似關(guān)公戰(zhàn)秦瓊疾渴,雖然關(guān)公和秦瓊都是武將,但其實(shí)沒(méi)有太多可比性屯仗。
BASE
BASE 是指基本可用(Basically Available)搞坝、軟狀態(tài)( Soft State)、最終一致性( Eventual Consistency)魁袜,核心思想是即使無(wú)法做到強(qiáng)一致性(CAP 的一致性就是強(qiáng)一致性)桩撮,但應(yīng)用可以采用適合的方式達(dá)到最終一致性敦第。
1. 基本可用(Basically Available)
分布式系統(tǒng)在出現(xiàn)故障時(shí),允許損失部分可用性店量,即保證核心可用芜果。
這里的關(guān)鍵詞是“部分”和“核心”,具體選擇哪些作為可以損失的業(yè)務(wù)融师,哪些是必須保證的業(yè)務(wù)右钾,是一項(xiàng)有挑戰(zhàn)的工作。例如旱爆,對(duì)于一個(gè)用戶(hù)管理系統(tǒng)來(lái)說(shuō)舀射,“登錄”是核心功能,而“注冊(cè)”可以算作非核心功能怀伦。因?yàn)槲醋?cè)的用戶(hù)本來(lái)就還沒(méi)有使用系統(tǒng)的業(yè)務(wù)脆烟,注冊(cè)不了最多就是流失一部分用戶(hù),而且這部分用戶(hù)數(shù)量較少房待。如果用戶(hù)已經(jīng)注冊(cè)但無(wú)法登錄邢羔,那就意味用戶(hù)無(wú)法使用系統(tǒng)。例如桑孩,充了錢(qián)的游戲不能玩了张抄、云存儲(chǔ)不能用了……這些會(huì)對(duì)用戶(hù)造成較大損失,而且登錄用戶(hù)數(shù)量遠(yuǎn)遠(yuǎn)大于新注冊(cè)用戶(hù)洼怔,影響范圍更大。
2. 軟狀態(tài)(Soft State)
允許系統(tǒng)存在中間狀態(tài)左驾,而該中間狀態(tài)不會(huì)影響系統(tǒng)整體可用性镣隶。這里的中間狀態(tài)就是 CAP 理論中的數(shù)據(jù)不一致。
3. 最終一致性(Eventual Consistency)
系統(tǒng)中的所有數(shù)據(jù)副本經(jīng)過(guò)一定時(shí)間后诡右,最終能夠達(dá)到一致的狀態(tài)安岂。
這里的關(guān)鍵詞是“一定時(shí)間” 和 “最終”,“一定時(shí)間”和數(shù)據(jù)的特性是強(qiáng)關(guān)聯(lián)的帆吻,不同的數(shù)據(jù)能夠容忍的不一致時(shí)間是不同的域那。舉一個(gè)微博系統(tǒng)的例子,用戶(hù)賬號(hào)數(shù)據(jù)最好能在 1 分鐘內(nèi)就達(dá)到一致?tīng)顟B(tài)猜煮,因?yàn)橛脩?hù)在 A 節(jié)點(diǎn)注冊(cè)或者登錄后次员,1 分鐘內(nèi)不太可能立刻切換到另外一個(gè)節(jié)點(diǎn),但 10 分鐘后可能就重新登錄到另外一個(gè)節(jié)點(diǎn)了王带;而用戶(hù)發(fā)布的最新微博淑蔚,可以容忍 30 分鐘內(nèi)達(dá)到一致?tīng)顟B(tài),因?yàn)閷?duì)于用戶(hù)來(lái)說(shuō)愕撰,看不到某個(gè)明星發(fā)布的最新微博刹衫,用戶(hù)是無(wú)感知的醋寝,會(huì)認(rèn)為明星沒(méi)有發(fā)布微博〈伲“最終”的含義就是不管多長(zhǎng)時(shí)間音羞,最終還是要達(dá)到一致性的狀態(tài)。
BASE 理論本質(zhì)上是對(duì) CAP 的延伸和補(bǔ)充仓犬,更具體地說(shuō)嗅绰,是對(duì) CAP 中 AP 方案的一個(gè)補(bǔ)充。前面在剖析 CAP 理論時(shí)婶肩,提到了其實(shí)和 BASE 相關(guān)的兩點(diǎn):
CAP 理論是忽略延時(shí)的办陷,而實(shí)際應(yīng)用中延時(shí)是無(wú)法避免的。
這一點(diǎn)就意味著完美的 CP 場(chǎng)景是不存在的律歼,即使是幾毫秒的數(shù)據(jù)復(fù)制延遲民镜,在這幾毫秒時(shí)間間隔內(nèi),系統(tǒng)是不符合 CP 要求的险毁。因此 CAP 中的 CP 方案制圈,實(shí)際上也是實(shí)現(xiàn)了最終一致性,只是“一定時(shí)間”是指幾毫秒而已畔况。
AP 方案中犧牲一致性只是指分區(qū)期間鲸鹦,而不是永遠(yuǎn)放棄一致性。
這一點(diǎn)其實(shí)就是 BASE 理論延伸的地方跷跪,分區(qū)期間犧牲一致性馋嗜,但分區(qū)故障恢復(fù)后,系統(tǒng)應(yīng)該達(dá)到最終一致性吵瞻。
綜合上面的分析葛菇,ACID 是數(shù)據(jù)庫(kù)事務(wù)完整性的理論,CAP 是分布式系統(tǒng)設(shè)計(jì)理論橡羞,BASE 是 CAP 理論中 AP 方案的延伸眯停。
小結(jié)
今天我為你講了深入理解 CAP 理論所需要特別關(guān)注的細(xì)節(jié)點(diǎn),以及 ACID 和 BASE 兩個(gè)相似的術(shù)語(yǔ)卿泽,這些技術(shù)細(xì)節(jié)在架構(gòu)設(shè)計(jì)中非常關(guān)鍵莺债,希望對(duì)你有所幫助。
這就是今天的全部?jī)?nèi)容签夭,留一道思考題給你吧齐邦,假如你來(lái)設(shè)計(jì)電商網(wǎng)站的高可用系統(tǒng),按照 CAP 理論的要求第租,你會(huì)如何設(shè)計(jì)侄旬?
歡迎你把答案寫(xiě)到留言區(qū),和我一起討論煌妈。相信經(jīng)過(guò)深度思考的回答儡羔,也會(huì)讓你對(duì)知識(shí)的理解更加深刻宣羊。(編輯亂入:精彩的留言有機(jī)會(huì)獲得豐厚福利哦!)