漫話(huà):如何給女朋友解釋什么是3PC?
一頓愉快的小火鍋之后,悠哉悠哉的回家了,于是只能開(kāi)始新一輪的家庭科普了。
分布式一致性
不過(guò)還是要簡(jiǎn)單交代下背景。我們以飯店的后廚為例介紹過(guò):
隨著飯店的發(fā)展,慢慢的從只有一個(gè)廚師演變成有多個(gè)廚師,進(jìn)而演變成有洗菜工、配菜師、廚師等多個(gè)職位。
當(dāng)有了多種分工之后,就勢(shì)必需要協(xié)調(diào)這些人之間的合作。
比如餐廳客人點(diǎn)了一份番茄炒蛋,然后后廚開(kāi)始準(zhǔn)備起來(lái),洗菜工開(kāi)始洗西紅柿,配菜師開(kāi)始準(zhǔn)備雞蛋,廚師開(kāi)始向鍋內(nèi)加油準(zhǔn)備炒菜。這是一種很正常的情況。
但是,如果消息傳達(dá)的不到位,或者洗菜師傅臨時(shí)不在廚房等,就會(huì)導(dǎo)致有的人已經(jīng)開(kāi)始準(zhǔn)備起來(lái),但是有的人并沒(méi)有準(zhǔn)備。
這就像是一個(gè)分布式系統(tǒng)一樣的,當(dāng)我們?cè)陔娚叹W(wǎng)站下單的時(shí)候,需要有多個(gè)分布式服務(wù)同時(shí)服務(wù),如支付系統(tǒng)進(jìn)行支付、紅包系統(tǒng)進(jìn)行紅包扣減、庫(kù)存系統(tǒng)扣減庫(kù)存、物流系統(tǒng)更新物流信息等。
但是,如果其中某一個(gè)系統(tǒng)在執(zhí)行過(guò)程中失敗了,或者由于網(wǎng)絡(luò)原因沒(méi)有收到請(qǐng)求,那么,整個(gè)系統(tǒng)可能就有不一致的現(xiàn)象了,即:付了錢(qián),扣了紅包,但是庫(kù)存沒(méi)有扣減。
這就是所謂的分布式系統(tǒng)的數(shù)據(jù)一致性問(wèn)題。
為了解決分布式一致性問(wèn)題,人們提出了很多解決方案,其中比較重要的就是2PC和3PC。之前我們介紹過(guò)了2PC,其實(shí)就是相當(dāng)于在后廚引入一個(gè)協(xié)調(diào)者,他負(fù)責(zé)統(tǒng)籌所有參與者。
二階段提交的算法思路是在分布式系統(tǒng)中引入了協(xié)調(diào)者,參與者將操作成敗通知協(xié)調(diào)者,再由協(xié)調(diào)者根據(jù)所有參與者的反饋情報(bào)決定各參與者是否要提交操作還是中止操作。
那么整個(gè)操作被分為兩個(gè)階段:第一階段:準(zhǔn)備階段(投票階段)和第二階段:提交階段(執(zhí)行階段)
但是,同時(shí),2PC也存在一些缺點(diǎn),如同步阻塞問(wèn)題、單點(diǎn)故障問(wèn)題、無(wú)法100%保證數(shù)據(jù)一致性等問(wèn)題。所以人們?cè)?PC的基礎(chǔ)上提出了3PC算法。
三階段提交
在二階段提交(2PC)存在諸多問(wèn)題的情況下,人們提出了三階段提交(3PC),主要用來(lái)解決2PC存在的一些問(wèn)題(但是這里提一句,3PC并沒(méi)徹底解決2PC存在的所有問(wèn)題)。
有一個(gè)人想要五黑玩王者榮耀,于是他開(kāi)始聯(lián)系自己的小伙伴們。
采用2PC的算法召集好友開(kāi)黑時(shí),會(huì)發(fā)生以下事情:
組織者:小A,我們準(zhǔn)備玩王者榮耀,你要是可以來(lái)參加的話(huà),現(xiàn)在你就登錄游戲,然后在游戲好友上給我回復(fù)個(gè)消息。
小A登錄自己的游戲賬號(hào),然后告訴組織者:小A已就位。
組織者:小B、小C、小D,我們準(zhǔn)備玩王者榮耀,你要是可以來(lái)參加的話(huà),現(xiàn)在你就登錄游戲,然后在游戲好友上給我回復(fù)個(gè)消息。
小B、小C、小D分別登錄自己的游戲賬號(hào),然后告訴組織者:小B、小C、小D已就位。
組織者發(fā)現(xiàn)所有人都就位了,于是在游戲上逐一通知大家,
組織者:小A,我邀請(qǐng)你了,你進(jìn)來(lái)吧。
小A接受邀請(qǐng)
組織者:小B、小C、小D,我邀請(qǐng)你了,你進(jìn)來(lái)吧。
小小B、小C、小D接收邀請(qǐng)
接著我們看下,如果采用3PC的方式組織王者榮耀五黑,會(huì)發(fā)生怎樣的事情:
組織者:小A,我們想定在晚上8點(diǎn),你有時(shí)間嘛?有時(shí)間你就說(shuō)YES,沒(méi)有你就說(shuō)NO,然后我還會(huì)再去問(wèn)其他人,這段時(shí)間你可先去干你自己的事兒,不用一直等著我。
小A:好的,我有時(shí)間。
組織者:小B、小C、小D,我們想定在晚上8點(diǎn)王者榮耀五黑……不用一直等我。
組織者收集完大家的時(shí)間情況了,一看大家都有時(shí)間,那么就再次通知大家。(協(xié)調(diào)者接收到所有YES指令)
組織者:小A,我們確定了晚上8點(diǎn)王者榮耀五黑,你要把段時(shí)間空出來(lái),你不能再安排其他的事兒了。然后我會(huì)逐個(gè)通知其他朋友,通知完之后我會(huì)再來(lái)和你確認(rèn)一下,還有啊,如果我沒(méi)有特意給你打電話(huà),你就8點(diǎn)上號(hào)就行了。對(duì)了,你確定能來(lái)是吧?
小A順手設(shè)置了晚上8點(diǎn)鬧鐘,然后跟組織者說(shuō),我可以去。
組織者:小B,我們決定了晚上8點(diǎn)王者榮耀五黑……你就8點(diǎn)上號(hào)就行了。
組織者通知完一圈之后。所有朋友都跟他說(shuō):”我已經(jīng)把8點(diǎn)這個(gè)時(shí)間段空出來(lái)了”。于是,他在8點(diǎn)的時(shí)候這一天又挨個(gè)打了一遍電話(huà)告訴他們:嘿,現(xiàn)在你們可以上號(hào)啦。。。。
小A、小B、小C、小D:我已經(jīng)登錄了,你拉我吧。
組織者邀請(qǐng)A、B、C等加入游戲。
以上過(guò)程,就是一個(gè)典型的三階段提交(3PC)的過(guò)程,和2PC相比,3PC多了一個(gè)步驟,就是提前詢(xún)問(wèn)所以參與者是否都能參與,并且所有人都同意后再次通知大家登錄游戲。
所謂3PC,就是把2PC的準(zhǔn)備階段再次一分為二,組成了三階段。
在第一階段,只是詢(xún)問(wèn)所有參與者是否可以執(zhí)行事務(wù)操作,并不在本階段執(zhí)行事務(wù)操作。當(dāng)協(xié)調(diào)者收到所有的參與者都返回YES時(shí),在第二階段才執(zhí)行事務(wù)操作,然后在第三階段在執(zhí)行commit或者rollback。
這樣三階段提交就有CanCommit(事務(wù)詢(xún)問(wèn))、PreCommit(事務(wù)執(zhí)行)、DoCommit(事務(wù)提交)三個(gè)階段。
3PC的處理過(guò)程
和二階段提交對(duì)比,三階段提交主要是在2PC的第一階段和第二階段中插入一個(gè)準(zhǔn)備階段。保證了在最后提交階段之前各參與節(jié)點(diǎn)的狀態(tài)是一致的。
接下來(lái)看看具體執(zhí)行過(guò)程。
CanCommit
3PC的CanCommit階段其實(shí)和2PC的準(zhǔn)備階段很像。協(xié)調(diào)者向參與者發(fā)送commit請(qǐng)求,參與者如果可以提交就返回Yes響應(yīng),否則返回No響應(yīng)。
1、事務(wù)詢(xún)問(wèn):協(xié)調(diào)者向參與者發(fā)送CanCommit請(qǐng)求。詢(xún)問(wèn)是否可以執(zhí)行事務(wù)提交操作。然后開(kāi)始等待參與者的響應(yīng)。
2、響應(yīng)反饋:參與者接到CanCommit請(qǐng)求之后,正常情況下,如果其自身認(rèn)為可以順利執(zhí)行事務(wù),則返回YES響應(yīng),并進(jìn)入預(yù)備狀態(tài)。否則反饋NO
PreCommit階段
協(xié)調(diào)者根據(jù)CanCommit階段參與者的反應(yīng)情況來(lái)決定是否可以進(jìn)行事務(wù)的PreCommit操作。
假如協(xié)調(diào)者從所有的參與者獲得的反饋都是YES響應(yīng),那么就會(huì)執(zhí)行事務(wù)的預(yù)執(zhí)行:
1、發(fā)送預(yù)提交請(qǐng)求:協(xié)調(diào)者向參與者發(fā)送PreCommit請(qǐng)求,并進(jìn)入Prepared階段。
2、事務(wù)預(yù)提交:參與者接收到PreCommit請(qǐng)求后,會(huì)執(zhí)行事務(wù)操作,并將undo和redo信息記錄到事務(wù)日志中。
3、響應(yīng)反饋:如果參與者成功的執(zhí)行了事務(wù)操作,則返回ACK響應(yīng),同時(shí)開(kāi)始等待最終指令。
假如有任何一個(gè)參與者向協(xié)調(diào)者發(fā)送了NO響應(yīng),或者等待超時(shí)之后,協(xié)調(diào)者都沒(méi)有接到參與者的響應(yīng),那么就執(zhí)行事務(wù)的中斷。
1、發(fā)送中斷請(qǐng)求:協(xié)調(diào)者向所有參與者發(fā)送abort請(qǐng)求。
2、中斷事務(wù):參與者收到來(lái)自協(xié)調(diào)者的abort請(qǐng)求之后(或超時(shí)之后,仍未收到協(xié)調(diào)者的請(qǐng)求),執(zhí)行事務(wù)的中斷。
doCommit階段
該階段進(jìn)行真正的事務(wù)提交,也可以分為以下兩種情況。
如果協(xié)調(diào)證收到所有參與者的事務(wù)執(zhí)行后的ACK響應(yīng),則發(fā)生如下事情:
1、發(fā)送提交請(qǐng)求:協(xié)調(diào)接收到參與者發(fā)送的ACK響應(yīng),那么他將從預(yù)提交狀態(tài)進(jìn)入到提交狀態(tài)。并向所有參與者發(fā)送doCommit請(qǐng)求。
2、事務(wù)提交:參與者接收到doCommit請(qǐng)求之后,執(zhí)行正式的事務(wù)提交。并在完成事務(wù)提交之后釋放所有事務(wù)資源。
3、響應(yīng)反饋:事務(wù)提交完之后,向協(xié)調(diào)者發(fā)送Ack響應(yīng)。
4、完成事務(wù):協(xié)調(diào)者接收到所有參與者的ack響應(yīng)之后,完成事務(wù)。
如果協(xié)調(diào)者沒(méi)有接收到參與者發(fā)送的ACK響應(yīng)(可能是接受者發(fā)送的不是ACK響應(yīng),也可能響應(yīng)超時(shí)),那么就會(huì)執(zhí)行中斷事務(wù)。
1、發(fā)送中斷請(qǐng)求:協(xié)調(diào)者向所有參與者發(fā)送abort請(qǐng)求
2、事務(wù)回滾:參與者接收到abort請(qǐng)求之后,利用其在階段二記錄的undo信息來(lái)執(zhí)行事務(wù)的回滾操作,并在完成回滾之后釋放所有的事務(wù)資源。
3、反饋結(jié)果:參與者完成事務(wù)回滾之后,向協(xié)調(diào)者發(fā)送ACK消息
4、中斷事務(wù):協(xié)調(diào)者接收到參與者反饋的ACK消息之后,執(zhí)行事務(wù)的中斷。
還有一種情況,如果參與者無(wú)法及時(shí)接收到來(lái)自協(xié)調(diào)者的doCommit或者abort請(qǐng)求時(shí),會(huì)在等待超時(shí)之后,會(huì)繼續(xù)進(jìn)行事務(wù)的提交。
以上,就是3PC的三個(gè)主要階段的操作流程。
3PC比2PC好在哪?
1、降低同步阻塞。
在3PC中,第一階段并沒(méi)有讓參與者直接執(zhí)行事務(wù),而是在第二階段才會(huì)讓參與者進(jìn)行事務(wù)的執(zhí)行。大大降低了阻塞的概率和時(shí)長(zhǎng)。并且,在3PC中,如果參與者未收到協(xié)調(diào)者的消息,那么他會(huì)在等待一段時(shí)間后自動(dòng)執(zhí)行事務(wù)的commit,而不是一直阻塞。
2、提升了數(shù)據(jù)一致性
2PC中有一種情況會(huì)導(dǎo)致數(shù)據(jù)不一致,如在2PC的階段二中,當(dāng)協(xié)調(diào)者向參與者發(fā)送commit請(qǐng)求之后,發(fā)生了網(wǎng)絡(luò)異常,只有一部分參與者接受到了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)象。
這種情況在3PC的場(chǎng)景中得到了很好的解決,因?yàn)樵?PC中,如果參與者沒(méi)有收到協(xié)調(diào)者的消息時(shí),他不會(huì)一直阻塞,過(guò)一段時(shí)間之后,他會(huì)自動(dòng)執(zhí)行事務(wù)。這就解決了那種協(xié)調(diào)者發(fā)出commit之后。
另外,2PC還有個(gè)問(wèn)題無(wú)法解決。那就是協(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)提交。
這種情況在3PC中是有辦法解決的,因?yàn)樵?PC中,選出新的協(xié)調(diào)者之后,他可以咨詢(xún)所有參與者的狀態(tài),如果有某一個(gè)處于commit狀態(tài)或者prepare-commit狀態(tài),那么他就可以通知所有參與者執(zhí)行commit,否則就通知大家rollback。因?yàn)?PC的第三階段一旦有機(jī)器執(zhí)行了commit,那必然第一階段大家都是同意commit的,所以可以放心執(zhí)行commit。
3PC無(wú)法解決的問(wèn)題
在doCommit階段,如果參與者無(wú)法及時(shí)接收到來(lái)自協(xié)調(diào)者的doCommit或者abort請(qǐng)求時(shí),會(huì)在等待超時(shí)之后,會(huì)繼續(xù)進(jìn)行事務(wù)的提交。
所以,由于網(wǎng)絡(luò)原因,協(xié)調(diào)者發(fā)送的abort響應(yīng)沒(méi)有及時(shí)被參與者接收到,那么參與者在等待超時(shí)之后執(zhí)行了commit操作。這樣就和其他接到abort命令并執(zhí)行回滾的參與者之間存在數(shù)據(jù)不一致的情況。
所以,我們可以認(rèn)為,無(wú)論是二階段提交還是三階段提交都無(wú)法徹底解決分布式的一致性問(wèn)題。
Google Chubby的作者M(jìn)ike Burrows說(shuō)過(guò):
there is only one consensus protocol, and that’s Paxos” – all other approaches are just broken versions of Paxos。
意即世上只有一種一致性算法,那就是Paxos,所有其他一致性算法都是Paxos算法的不完整版。