漫話:如何給女朋友解釋什麼是2PC(二階段提交)?

  • 2019 年 10 月 4 日
  • 筆記

作者 漫話編程

周末晚上,正在家裏面看綜藝節目,突然女朋友跑過來找我打《王者榮耀》。

打了幾把遊戲,終於可以歇息一會了,準備繼續看我的綜藝,可是女朋友過來找我給他講講到底什麼是二階段提交。

分佈式一致性

還好我們之前專門給女朋友介紹過什麼是分佈式,要不然這個話題說來就話長了。

在之前介紹分佈式的時候,我們以飯店的後廚為例,今天繼續之前的例子來說說什麼是分佈式一致性。

隨着飯店的發展,慢慢的從只有一個廚師演變成有多個廚師,進而演變成有洗菜工、配菜師、廚師等多個職位。

當有了多種分工之後,就勢必需要協調這些人之間的合作。

比如餐廳客人點了一份番茄炒蛋,然後後廚開始準備起來,洗菜工開始洗西紅柿,配菜師開始準備雞蛋,廚師開始向鍋內加油準備炒菜。這是一種很正常的情況。

但是,如果消息傳達的不到位,或者洗菜師傅臨時不在廚房等,就會導致有的人已經開始準備起來,但是有的人並沒有準備。

這就像是一個分佈式系統一樣的,當我們在電商網站下單的時候,需要有多個分佈式服務同時服務,如支付系統進行支付、紅包系統進行紅包扣減、庫存系統扣減庫存、物流系統更新物流信息等。

但是,如果其中某一個系統在執行過程中失敗了,或者由於網絡原因沒有收到請求,那麼,整個系統可能就有不一致的現象了,即:付了錢,扣了紅包,但是庫存沒有扣減。

這就是所謂的分佈式系統的數據一致性問題。

二階段提交

之所以剛剛的例子中會出現一致性問題,就是因為每一個員工都只關注自己所做的事情,無法關注到其他人,那麼,要想保證整體的一致性,就需要在後廚中引入一個新的角色,負責統籌,這個角色來進行協調和調配所有人。

那麼,引入一個協調者負責協調所有參與者的工作,這個在分佈式系統中其實就是X/Open組織定義的分佈式事務處理模型,而二階段提交就是根據這一模型衍生出來的。

舉個例子,五個人相約打王者榮耀,想要一起玩需要以下幾個步驟:

有一個人想要五黑玩王者榮耀,於是他開始聯繫自己的小夥伴們。 組織者:小A,我們準備玩王者榮耀,你要是可以來參加的話,現在你就登錄遊戲,然後在遊戲好友上給我回復個消息。 小A登錄自己的遊戲賬號,然後告訴組織者:小A已就位。 組織者:小B、小C、小D,我們準備玩王者榮耀,你要是可以來參加的話,現在你就登錄遊戲,然後在遊戲好友上給我回復個消息。 小B、小C、小D分別登錄自己的遊戲賬號,然後告訴組織者:小B、小C、小D已就位。 組織者發現所有人都就位了,於是在遊戲上逐一通知大家, 組織者:小A,我邀請你了,你進來吧。 小A接受邀請 組織者:小B、小C、小D,我邀請你了,你進來吧。 小小B、小C、小D接收邀請 於是,5個人在王者峽谷愉快的玩耍了起來。

對於五個人開黑這個事務操作,在開始準備前五個人都是空閑狀態,忙着自己的事情。在組織者協調過之後,大家也要達成一個一致的狀態,即以下兩種情況之一:

  • 1、五個人愉快的開始一起玩遊戲
  • 2、五個人都退出遊戲,還是去忙自己的事情。

如果最後有一部分人在游戲裏一直等,另外一部分並沒有進入遊戲,那麼就是數據不一致了。

以上過程,就是一個典型的二階段提交(2PC)的過程,在分佈式系統中,也有同樣的問題,並且可以採用同樣的解決辦法。

在分佈式系統中,每個節點雖然可以知曉自己的操作時成功或者失敗,卻無法知道其他節點的操作的成功或失敗(只知道自己有時間可以玩王者榮耀,不知道其他人有沒有)。

當一個事務跨越多個節點時,為了保持事務的ACID特性,需要引入一個作為協調者的組件來統一掌控所有參與者的操作結果並最終指示這些節點是否要把操作結果進行真正的提交(組織者通知各位參與者一起進入遊戲房間)。

因此,二階段提交的算法思路可以概括為:參與者將操作成敗通知協調者,再由協調者根據所有參與者的反饋情報決定各參與者是否要提交操作還是中止操作。

所謂的兩個階段是指:第一階段:準備階段(投票階段)和第二階段:提交階段(執行階段)

準備階段

事務協調者給每個參與者發送Prepare消息,每個參與者要麼直接返回失敗(告知組織者自己沒時間,不能一起玩遊戲),要麼在本地執行事務(登錄王者榮耀),但不提交(先不開始遊戲)。

可以進一步將準備階段分為以下三個步驟:

  • 1)協調者節點向所有參與者節點詢問是否可以執行提交操作,並開始等待各參與者節點的響應。(詢問是否可以一起玩遊戲)
  • 2)參與者節點執行詢問發起為止的所有事務操作,並將Undo信息和Redo信息寫入日誌。(登錄王者榮耀遊戲)
  • 3)各參與者節點響應協調者節點發起的詢問。如果參與者節點的事務操作實際執行成功,則它返回一個」同意」消息;(告知組織者自己已經登錄成功)如果參與者節點的事務操作實際執行失敗,則它返回一個」中止」消息。(告知組織者自己暫時無法一起玩遊戲,如自己的賬號被限制無法打排位)

提交階段

如果協調者收到了參與者的失敗消息或者超時(有人不能一起玩遊戲,或者一直沒有回復),直接給每個參與者發送回滾消息(告知其他人,暫時取消遊戲);否則,發送提交消息(邀請大家進入遊戲房間);參與者根據協調者的指令執行提交或者回滾操作(進入房間一起玩遊戲或者退出遊戲去做別的事情)。

接下來分兩種情況分別討論提交階段的過程。

當協調者節點從所有參與者節點獲得的相應消息都為」同意」時:

  • 1)協調者節點向所有參與者節點發出」正式提交」的請求(要求所有已登錄的朋友加入遊戲房間)。
  • 2)參與者節點正式完成操作,並釋放在整個事務期間內佔用的資源(接受邀請,進入房間)。
  • 3)參與者節點向協調者節點發送」完成」消息(點擊"準備",進入準備狀態)。
  • 4)協調者節點受到所有參與者節點反饋的」完成」消息後,完成事務(進入王者峽谷)。

如果任一參與者節點在第一階段返回的響應消息為」中止」,或者 協調者節點在第一階段的詢問超時之前無法獲取所有參與者節點的響應消息時:

  • 1)協調者節點向所有參與者節點發出」回滾操作」的請求(告知所有人取消遊戲)。
  • 2)參與者節點利用之前寫入的Undo信息執行回滾,並釋放在整個事務期間內佔用的資源(退出遊戲,去做自己的事情)。
  • 3)參與者節點向協調者節點發送」回滾完成」消息(告訴組織者自己知道了,後面有機會再玩)。
  • 4)協調者節點受到所有參與者節點反饋的」回滾完成」消息後,取消事務(取消本次遊戲活動)。

2PC的缺點

以上過程其實是有一些缺點的,如

1、當參與者收到組織者的消息之後,需要登錄遊戲,在遊戲中等待組織者的再次邀請,這個過程比較浪費時間。

2、如果在這個過程中,組織者突然有什麼事情被打斷了,那麼那些已經進入遊戲的參與者就可能一直等下去。

3、在所有人都登錄遊戲之後,組織者通過邀請要求所有人加入他的房間,這時候如果有一些網絡異常、或者參與者沒在手機前面等情況,可能會有一部分用戶加入了房間,有一部分沒加入。

4、如果組織者在遊戲中開始邀請所有參與者的時候,他邀請了第一個人之後,他和這個被他邀請的人都掉線了。這時候另外三個人就不知道到底應該怎麼辦了。

以上問題,分佈式系統的2PC階段一樣存在,分別對應以下問題:

1、同步阻塞問題。執行過程中,所有參與節點都是事務阻塞型的。當參與者佔有公共資源時,其他第三方節點訪問公共資源不得不處於阻塞狀態。

2、單點故障。由於協調者的重要性,一旦協調者發生故障。參與者會一直阻塞下去。尤其在第二階段,協調者發生故障,那麼所有的參與者還都處於鎖定事務資源的狀態中,而無法繼續完成事務操作。(如果是協調者掛掉,可以重新選舉一個協調者,但是無法解決因為協調者宕機導致的參與者處於阻塞狀態的問題)

3、數據不一致。在二階段提交的階段二中,當協調者向參與者發送commit請求之後,發生了局部網絡異常或者在發送commit請求過程中協調者發生了故障,這回導致只有一部分參與者接受到了commit請求。而在這部分參與者接到commit請求之後就會執行commit操作。但是其他部分未接到commit請求的機器則無法執行事務提交。於是整個分佈式系統便出現了數據部一致性的現象。

4、二階段無法解決的問題:協調者再發出commit消息之後宕機,而唯一接收到這條消息的參與者同時也宕機了。那麼即使協調者通過選舉協議產生了新的協調者,這條事務的狀態也是不確定的,沒人知道事務是否被已經提交。

總結一下,就是說2PC並不是完美的,他存在着同步阻塞問題、單點故障問題、無法100%保證數據一致性等問題。