一、分布式數(shù)據(jù)一致性
在分布式系統(tǒng)中,為了保證數(shù)據(jù)的高可用,通常會(huì)將數(shù)據(jù)保留多個(gè)副本(replica)囱皿,這些副本會(huì)放置在不同的物理的機(jī)器上。
1.什么是數(shù)據(jù)一致性
在數(shù)據(jù)有多份副本的情況下忱嘹,如果網(wǎng)絡(luò)嘱腥、服務(wù)器或者軟件出現(xiàn)故障,會(huì)導(dǎo)致部分副本寫入成功拘悦,部分副本寫入失敗齿兔。這就造成各個(gè)副本之間的數(shù)據(jù)不一致,數(shù)據(jù)內(nèi)容沖突。
造成事實(shí)上的數(shù)據(jù)不一致愧驱。
2.CAP定理
CAP理論認(rèn)為在分布式的環(huán)境下設(shè)計(jì)和部署系統(tǒng)時(shí)慰技,有3個(gè)核心的需求:
Consistency,Availability和Partition Tolerance组砚,即CAP吻商。
Consistency:一致性,這個(gè)和數(shù)據(jù)庫(kù)ACID的一致性類似糟红,但這里關(guān)注的所有數(shù)據(jù)節(jié)點(diǎn)上的數(shù)據(jù)一致性和正確性艾帐,而數(shù)據(jù)庫(kù)的ACID關(guān)注的是在在一個(gè)事務(wù)內(nèi),對(duì)數(shù)據(jù)的一些約束盆偿。系統(tǒng)在執(zhí)行過(guò)某項(xiàng)操作后仍然處于一致的狀態(tài)柒爸。在分布式系統(tǒng)中,更新操作執(zhí)行成功后所有的用戶都應(yīng)該讀取到最新值事扭。
Availability:可用性捎稚,每一個(gè)操作總是能夠在一定時(shí)間內(nèi)返回結(jié)果。需要注意“一定時(shí)間”和“返回結(jié)果”求橄〗褚埃“一定時(shí)間”是指,系統(tǒng)結(jié)果必須在給定時(shí)間內(nèi)返回罐农√跛“返回結(jié)果”是指系統(tǒng)返回操作成功或失敗的結(jié)果。
Partition Tolerance:分區(qū)容忍性涵亏,是否可以對(duì)數(shù)據(jù)進(jìn)行分區(qū)宰睡。這是考慮到性能和可伸縮性。
3.數(shù)據(jù)一致性模型
一些分布式系統(tǒng)通過(guò)復(fù)制數(shù)據(jù)來(lái)提高系統(tǒng)的可靠性和容錯(cuò)性气筋,并且將數(shù)據(jù)的不同的副本存放在不同的機(jī)器拆内。
強(qiáng)一致性:
當(dāng)更新操作完成之后,任何多個(gè)后續(xù)進(jìn)程或者線程的訪問(wèn)都會(huì)返回最新的更新過(guò)的值裆悄。這種是對(duì)用戶最友好的矛纹,就是用戶上一次寫什么臂聋,下一次就保證能讀到什么光稼。根據(jù) CAP 理論,這種實(shí)現(xiàn)需要犧牲可用性孩等。
弱一致性:
系統(tǒng)并不保證續(xù)進(jìn)程或者線程的訪問(wèn)都會(huì)返回最新的更新過(guò)的值艾君。用戶讀到某一操作對(duì)系統(tǒng)特定數(shù)據(jù)的更新需要一段時(shí)間,我們稱這段時(shí)間為“不一致性窗口”肄方。系統(tǒng)在數(shù)據(jù)寫入成功之后冰垄,不承諾立即可以讀到最新寫入的值,也不會(huì)具體的承諾多久之后可以讀到权她。
最終一致性:
是弱一致性的一種特例虹茶。系統(tǒng)保證在沒(méi)有后續(xù)更新的前提下逝薪,系統(tǒng)最終返回上一次更新操作的值。在沒(méi)有故障發(fā)生的前提下蝴罪,不一致窗口的時(shí)間主要受通信延遲董济,系統(tǒng)負(fù)載和復(fù)制副本的個(gè)數(shù)影響。DNS 是一個(gè)典型的最終一致性系統(tǒng)要门。
二虏肾、典型的分布式事務(wù)實(shí)例
跨行轉(zhuǎn)賬問(wèn)題是一個(gè)典型的分布式事務(wù),用戶A向B的一個(gè)轉(zhuǎn)賬1000欢搜,要進(jìn)行A的余額-1000封豪,B的余額+1000,顯然必須保證這兩個(gè)操作的事務(wù)性炒瘟。
類似的還有吹埠,電商系統(tǒng)中,當(dāng)有用戶下單后疮装,除了在訂單表插入記藻雌,還要在商品表更新庫(kù)存等,特別是隨著微服務(wù)架構(gòu)的流行斩个,分布式事務(wù)的場(chǎng)景更變得更普遍胯杭。
三、兩階段提交協(xié)議
兩階段提交協(xié)議是協(xié)調(diào)所有分布式原子事務(wù)參與者受啥,并決定提交或取消(回滾)的分布式算法做个。
1.協(xié)議參與者
在兩階段提交協(xié)議中,系統(tǒng)一般包含兩類機(jī)器(或節(jié)點(diǎn)):一類為協(xié)調(diào)者(coordinator)滚局,通常一個(gè)系統(tǒng)中只有一個(gè)居暖;另一類為事務(wù)參與者(participants,cohorts或workers)藤肢,一般包含多個(gè)太闺,在數(shù)據(jù)存儲(chǔ)系統(tǒng)中可以理解為數(shù)據(jù)副本的個(gè)數(shù)。協(xié)議中假設(shè)每個(gè)節(jié)點(diǎn)都會(huì)記錄寫前日志(write-ahead log)并持久性存儲(chǔ)嘁圈,即使節(jié)點(diǎn)發(fā)生故障日志也不會(huì)丟失省骂。協(xié)議中同時(shí)假設(shè)節(jié)點(diǎn)不會(huì)發(fā)生永久性故障而且任意兩個(gè)節(jié)點(diǎn)都可以互相通信。
2.兩個(gè)階段的執(zhí)行
1.請(qǐng)求階段(commit-request phase,或稱表決階段,voting phase)
在請(qǐng)求階段碍扔,協(xié)調(diào)者將通知事務(wù)參與者準(zhǔn)備提交或取消事務(wù),然后進(jìn)入表決過(guò)程轧粟。
在表決過(guò)程中,參與者將告知協(xié)調(diào)者自己的決策:同意(事務(wù)參與者本地作業(yè)執(zhí)行成功)或取消(本地作業(yè)執(zhí)行故障)。
2.提交階段(commit phase)
在該階段兰吟,協(xié)調(diào)者將基于第一個(gè)階段的投票結(jié)果進(jìn)行決策:提交或取消通惫。
當(dāng)且僅當(dāng)所有的參與者同意提交事務(wù)協(xié)調(diào)者才通知所有的參與者提交事務(wù),否則協(xié)調(diào)者將通知所有的參與者取消事務(wù)混蔼。
參與者在接收到協(xié)調(diào)者發(fā)來(lái)的消息后將執(zhí)行響應(yīng)的操作讽膏。
3.兩階段提交的缺點(diǎn)
1.同步阻塞問(wèn)題。執(zhí)行過(guò)程中拄丰,所有參與節(jié)點(diǎn)都是事務(wù)阻塞型的府树。
當(dāng)參與者占有公共資源時(shí),其他第三方節(jié)點(diǎn)訪問(wèn)公共資源不得不處于阻塞狀態(tài)料按。
2.單點(diǎn)故障奄侠。由于協(xié)調(diào)者的重要性,一旦協(xié)調(diào)者發(fā)生故障载矿。
參與者會(huì)一直阻塞下去垄潮。尤其在第二階段,協(xié)調(diào)者發(fā)生故障闷盔,那么所有的參與者還都處于鎖定事務(wù)資源的狀態(tài)中弯洗,而無(wú)法繼續(xù)完成事務(wù)操作。(如果是協(xié)調(diào)者掛掉逢勾,可以重新選舉一個(gè)協(xié)調(diào)者牡整,但是無(wú)法解決因?yàn)閰f(xié)調(diào)者宕機(jī)導(dǎo)致的參與者處于阻塞狀態(tài)的問(wèn)題)
3.數(shù)據(jù)不一致。在二階段提交的階段二中溺拱,當(dāng)協(xié)調(diào)者向參與者發(fā)送commit請(qǐng)求之后逃贝,發(fā)生了局部網(wǎng)絡(luò)異常或者在發(fā)送commit請(qǐng)求過(guò)程中協(xié)調(diào)者發(fā)生了故障迫摔,這回導(dǎo)致只有一部分參與者接受到了commit請(qǐng)求沐扳。
而在這部分參與者接到commit請(qǐng)求之后就會(huì)執(zhí)行commit操作。但是其他部分未接到commit請(qǐng)求的機(jī)器則無(wú)法執(zhí)行事務(wù)提交句占。于是整個(gè)分布式系統(tǒng)便出現(xiàn)了數(shù)據(jù)部一致性的現(xiàn)象沪摄。
4.兩階段提交無(wú)法解決的問(wèn)題
當(dāng)協(xié)調(diào)者出錯(cuò),同時(shí)參與者也出錯(cuò)時(shí)纱烘,兩階段無(wú)法保證事務(wù)執(zhí)行的完整性杨拐。
考慮協(xié)調(diào)者再發(fā)出commit消息之后宕機(jī),而唯一接收到這條消息的參與者同時(shí)也宕機(jī)了凹炸。
那么即使協(xié)調(diào)者通過(guò)選舉協(xié)議產(chǎn)生了新的協(xié)調(diào)者戏阅,這條事務(wù)的狀態(tài)也是不確定的,沒(méi)人知道事務(wù)是否被已經(jīng)提交啤它。
四、三階段提交協(xié)議
三階段提交協(xié)議在協(xié)調(diào)者和參與者中都引入超時(shí)機(jī)制,并且把兩階段提交協(xié)議的第一個(gè)階段拆分成了兩步:詢問(wèn)变骡,然后再鎖資源离赫,最后真正提交。
(1)三個(gè)階段的執(zhí)行
1.CanCommit階段
3PC的CanCommit階段其實(shí)和2PC的準(zhǔn)備階段很像塌碌。
協(xié)調(diào)者向參與者發(fā)送commit請(qǐng)求渊胸,參與者如果可以提交就返回Yes響應(yīng),否則返回No響應(yīng)台妆。
2.PreCommit階段
Coordinator根據(jù)Cohort的反應(yīng)情況來(lái)決定是否可以繼續(xù)事務(wù)的PreCommit操作翎猛。
根據(jù)響應(yīng)情況,有以下兩種可能接剩。
A.假如Coordinator從所有的Cohort獲得的反饋都是Yes響應(yīng)切厘,那么就會(huì)進(jìn)行事務(wù)的預(yù)執(zhí)行:
發(fā)送預(yù)提交請(qǐng)求。Coordinator向Cohort發(fā)送PreCommit請(qǐng)求懊缺,并進(jìn)入Prepared階段疫稿。
事務(wù)預(yù)提交。Cohort接收到PreCommit請(qǐng)求后鹃两,會(huì)執(zhí)行事務(wù)操作遗座,并將undo和redo信息記錄到事務(wù)日志中。
響應(yīng)反饋俊扳。如果Cohort成功的執(zhí)行了事務(wù)操作途蒋,則返回ACK響應(yīng),同時(shí)開始等待最終指令馋记。
B.假如有任何一個(gè)Cohort向Coordinator發(fā)送了No響應(yīng)碎绎,或者等待超時(shí)之后,Coordinator都沒(méi)有接到Cohort的響應(yīng)抗果,那么就中斷事務(wù):
發(fā)送中斷請(qǐng)求筋帖。Coordinator向所有Cohort發(fā)送abort請(qǐng)求。
中斷事務(wù)冤馏。Cohort收到來(lái)自Coordinator的abort請(qǐng)求之后(或超時(shí)之后日麸,仍未收到Cohort的請(qǐng)求),執(zhí)行事務(wù)的中斷逮光。
3.DoCommit階段
該階段進(jìn)行真正的事務(wù)提交代箭,也可以分為以下兩種情況:
執(zhí)行提交
A.發(fā)送提交請(qǐng)求。Coordinator接收到Cohort發(fā)送的ACK響應(yīng)涕刚,那么他將從預(yù)提交狀態(tài)進(jìn)入到提交狀態(tài)嗡综。并向所有Cohort發(fā)送doCommit請(qǐng)求。
B.事務(wù)提交杜漠。Cohort接收到doCommit請(qǐng)求之后极景,執(zhí)行正式的事務(wù)提交察净。并在完成事務(wù)提交之后釋放所有事務(wù)資源。
C.響應(yīng)反饋盼樟。事務(wù)提交完之后氢卡,向Coordinator發(fā)送ACK響應(yīng)。
D.完成事務(wù)晨缴。Coordinator接收到所有Cohort的ACK響應(yīng)之后译秦,完成事務(wù)。
中斷事務(wù)
Coordinator沒(méi)有接收到Cohort發(fā)送的ACK響應(yīng)(可能是接受者發(fā)送的不是ACK響應(yīng)击碗,也可能響應(yīng)超時(shí))筑悴,那么就會(huì)執(zhí)行中斷事務(wù)。
(2)三階段提交協(xié)議和兩階段提交協(xié)議的不同
對(duì)于協(xié)調(diào)者(Coordinator)和參與者(Cohort)都設(shè)置了超時(shí)機(jī)制(在2PC中稍途,只有協(xié)調(diào)者擁有超時(shí)機(jī)制阁吝,即如果在一定時(shí)間內(nèi)沒(méi)有收到cohort的消息則默認(rèn)失敗)晰房。
在2PC的準(zhǔn)備階段和提交階段之間求摇,插入預(yù)提交階段,使3PC擁有CanCommit殊者、PreCommit与境、DoCommit三個(gè)階段。
PreCommit是一個(gè)緩沖猖吴,保證了在最后提交階段之前各參與節(jié)點(diǎn)的狀態(tài)是一致的摔刁。
(3)三階段提交協(xié)議的缺點(diǎn)
如果進(jìn)入PreCommit后,Coordinator發(fā)出的是abort請(qǐng)求海蔽,假設(shè)只有一個(gè)Cohort收到并進(jìn)行了abort操作共屈,
而其他對(duì)于系統(tǒng)狀態(tài)未知的Cohort會(huì)根據(jù)3PC選擇繼續(xù)Commit,此時(shí)系統(tǒng)狀態(tài)發(fā)生不一致性党窜。
最本質(zhì)來(lái)講拗引,3PC避免了狀態(tài)停滯,在2PC有可能因?yàn)楦鞣N原因幌衣,產(chǎn)生狀態(tài)停滯矾削。但是3PC會(huì)讓狀態(tài)繼續(xù)下去,雖然有可能繼續(xù)下去是錯(cuò)的豁护。
3PC的問(wèn)題是明顯的(并沒(méi)有完全解決2PC的問(wèn)題3):
即如果進(jìn)入PreCommit后哼凯,Coordinator發(fā)出的是abort請(qǐng)求,如果只有一個(gè)Cohort收到并進(jìn)行了abort操作楚里,而其他對(duì)于系統(tǒng)狀態(tài)未知的Cohort會(huì)根據(jù)3PC選擇繼續(xù)Commit断部,那么系統(tǒng)的不一致性就存在了。所以無(wú)論是2PC還是3PC都存在問(wèn)題班缎。