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