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