從時序圖出發詳解PC算法

在分佈式系統中,爲了保證數據的高可用,通常,我們會將數據保留多個副本(replica),這些副本會放置在不同的物理的機器上。爲了對用戶提供正確的增\刪\改\差等語義,我們需要保證這些放置在不同物理機器上的副本是一致的。

而PC則是爲了解決不同物理機器上的副本的事務數據一致性的問題。

在分佈式系統中事務與單機應用事務不一樣的地方是:可能會因爲服務宕機或者網絡不通的情況而導致數據不一致,接下來讓我們按照這個思路來逐個分析1PC、2PC、3PC的優缺點:
(時序圖沒有畫得很詳細,需要詳細的圖可以搜索其他博客)

1PC

在這裏插入圖片描述

從網絡方面,在以下階段出現網絡異常:

①:客戶端無法發起事務,不會導致數據不一致。

②:向B系統發起事務請求失敗,A回滾,不會導致數據不一致。

③:B已經commit,而A請求超時,多次重試後rollback,出現數據不一致。

④:返回客戶端響應,AB已經達到數據一致性,不會導致數據不一致。

從服務宕機方面:

若在A向B發出commit請求後A宕機,則會導致B commit而Arollback。

1PC的有點是best effect。在所有分佈式事務算法中該運行速度是最快的,但是在遇到異常情況時候也容易造成數據的不一致,需要人工介入維護。

2PC

在這裏插入圖片描述

首先在參與者第二階段開始事務到全部完成事務這段時期,是存在數據不一致的情況的,但由於各個參與者是提前執行完事務,最後再進行確定,這段時期很短。下面分析的是會出現長時間的數據不一致狀態的情況。

從網絡方面,在以下階段出現網絡異常:

①-⑤:由於只是準備階段,若此期間出現網絡異常則取消事務,不會導致數據不一致。

⑥⑧:爲了減少同步造成的資源阻塞,許多事務管理器都採用了多線程的方式處理,因此當該階段中存在部分參與者網絡異常。這會導致只有一部分參與者接受到了commit請求。而在這部分參與者接到commit請求之後就會執行commit操作。但是其他部分未接到commit請求的機器則無法執行事務提交。於是便出現了數據不一致性的現象。

⑦⑨:參與已經commit,而事務管理器請求超時,多次重試後執行rollback,於是出現數據不一致。

⑩:返回客戶端響應,AB已經達到數據一致性,不會導致數據不一致。

從服務宕機方面:

情況一:協調者宕機了,參與者沒宕機

只要找一個協調者的替代者。當他成爲新的協調者的時候,詢問所有參與者的最後那條事務的執行情況,協調者就可以知道是應該做什麼樣的操作了。所以,這種情況不會導致數據不一致

情況二:參與者宕機了,協調者沒宕機

如果參與者宕機了。那麼之後的事情有兩種情況:

  • 第一種是宕機了就算了,沒有再恢復。那宕機的機器此時是不可用的狀態,裏面的數據不會被其他應用訪問,因此不會造成數據不一致
  • 第二種是宕機了之後又恢復了,參與者會詢問協調者如何保持數據一致性,協調者就會比對自己的事務執行記錄和該參與者的事務執行記錄,告訴該參與應該怎麼做來保持數據的一致性

存在問題:第一階段如果宕機的參與者返回的是否,而其他參與者返回的是是,那麼此時協調者按照剩下的參與者第二階段使用了commit操作。而後面之前宕機的參與者此時恢復了,爲了保持數據一致性需要強行commit麼?

情況三:參與者宕機了,協調者也宕機了

  • 協調者和參與者在第一階段宕機了:

    由於這時還沒有執行commit操作,新出來的協調者依次詢問各個參與者的情況,再決定是進行commit還是roolback。因爲還沒有commit,所以不會導致數據一致性問題。

  • 第二階段協調者和參與者宕機,宕機的這個參與者在掛之前並沒有接收到協調者的指令,或者接收到指令之後還沒來的及做commit或者roolback操作:

    這種情況下,當新的協調者被選出來之後,他同樣是詢問所有的參與者的情況。

    • 只要有機器執行了abort(roolback)操作或者第一階段有參與返回的信息是No的話,那就直接執行roolback操作。
    • 如果有機器執行了commit操作,那麼就直接執行commit操作。

    這樣,當掛掉的參與者恢復之後,只要按照協調者的指示進行事務的commit還是roolback操作就可以了。因爲掛掉的機器並沒有做commit或者roolback操作,而沒有掛掉的機器們和新的協調者又執行了同樣的操作,那麼這種情況不會導致數據不一致現象。

  • 第二階段協調者和參與者宕機,宕機的這個參與者在掛之前已經執行了操作。但是由於他宕機,沒有人知道他執行了什麼操作。

    大家肯定會想,在協調者的影響下參與者們不都是執行同一種操作麼,怎麼可能在一個事務中既出現commit又出現roolback的,我們可以看下下面這種情況:

    當除了宕機的參與者第一階段響應否,而其他參與者第一階段響應是,在第二階段時協調者調用了abort(roolback)操作,此時將要宕機的參與者執行了roolback操作。但其他參與者由於網絡問題沒有收到協調者的命令。當將要宕機的參與者回滾完畢並響應後,協調者跟該參與者都宕機了。後面協調者恢復後發現存活的參與者第一階段都響應是,那麼就會執行commit,這樣不就導致了數據不一致了麼。

    因此我們可以總結下出現該問題的原因是,在第一階段某個參與者未宕機的情況下存在否,同時因爲網絡異常導致除了將要宕機的參與者之外未收到abort指令,但是在該參與者宕機後整體不存在否,由此出現數據不一致。

    這種情況下,新的協調者被選出來之後,依次詢問各個參與者的情況,再決定是進行commit還是roolback。這樣新的協調者和所有沒掛掉的參與者就保持了數據的一致性,我們假定此時執行了commit。但是,當之前宕機的參與者恢復了,因爲該參與者之前已經執行完了之前的事務,如果他執行的是commit那還好,和其他的機器保持一致了,萬一他執行的是roolback操作就導致數據的不一致性。

所以,2PC協議中,如果出現協調者和參與者都宕機的情況,有可能導致數據不一致。

二階段提交看起來確實能夠提供原子性的操作,但是不幸的是,二階段提交還是有幾個缺點的:

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

2、單點故障:由於協調者的重要性,一旦協調者發生故障。參與者會一直阻塞下去。尤其在第二階段,協調者發生故障,那麼所有的參與者還都處於鎖定事務資源的狀態中,直到新的協調者被選舉出來。

3、數據不一致:在二階段提交的階段二中,當協調者向參與者發送commit請求之後,發生了局部網絡異常或者在發送請求過程中協調者與參與者發生了故障是會出現較長時間的數據不一致情況。其實2PC爲了高可用採用了最終一致性,因此在參與者第二階段開始事務到全部完成事務這段時期分佈式系統都會處於數據不一致的情況。

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

3PC

在這裏插入圖片描述
三階段提交(Three-phase commit),也叫三階段提交協議(Three-phase commit protocol),是二階段提交(2PC)的改進版本。

與兩階段提交不同的是,三階段提交有兩個改動點:

  • 引入超時機制。同時在協調者和參與者中都引入超時機制。
  • 在第一階段和第二階段中插入一個準備階段。保證了在最後提交階段之前各參與節點的狀態是一致的。

也就是說,除了引入超時機制之外,3PC把2PC的準備階段再次一分爲二,這樣三階段提交就有CanCommitPreCommitDoCommit三個階段。

從網絡方面,在以下階段出現網絡異常:

①-②:在該兩個階段中,並沒有事務的預提交,因此不會造成數據不一致。

③:如果只有部分參與者收到了pre-commit請求,在協調者嘗試超時後仍然沒有所有參與者返回ACK響應,則發送abort請求回滾。若此時⑤由於網絡原因,協調者發送的abort響應沒有及時被參與者接收到,那麼參與者在等待超時之後執行了commit操作。這樣就和其他接到abort命令並執行回滾的參與者之間存在數據不一致的情況。

④:如果參與者在收到了pre-commit請求後,執行了事務,在協調者嘗試超時後仍然沒有所有參與者返回ACK響應,則發送abort請求回滾。若此時⑤由於網絡原因,協調者發送的abort響應沒有及時被參與者接收到,那麼參與者在等待超時之後執行了commit操作。這樣就和其他接到abort命令並執行回滾的參與者之間存在數據不一致的情況。

⑤:若在協調者發送的abort響應沒有及時被參與者接收到,那麼參與者在等待超時之後執行了commit操作。這樣就和其他接到abort命令並執行回滾的參與者之間存在數據不一致的情況。

⑥:返回響應,參與者已經達到數據一致性,不會導致數據不一致。

從服務宕機方面:

情況一:協調者宕機了,參與者沒宕機

只要找一個協調者的替代者。當他成爲新的協調者的時候,詢問所有參與者的最後那條事務的執行情況,協調者就可以知道是應該做什麼樣的操作了。所以,這種情況不會導致數據不一致

情況二:參與者宕機了,協調者沒宕機

如果參與者宕機了。那麼之後的事情有兩種情況:

  • 第一種是宕機了就算了,沒有再恢復。那宕機的機器此時是不可用的狀態,裏面的數據不會被其他應用訪問,因此不會造成數據不一致
  • 第二種是宕機了之後又恢復了,參與者會詢問協調者如何保持數據一致性,協調者就會比對自己的事務執行記錄和該參與者的事務執行記錄,告訴該參與應該怎麼做來保持數據的一致性

情況三:參與者宕機了,協調者也宕機了

  • 協調者和參與者在第一、二階段宕機了:

    由於這時還沒有執行commit操作,新出來的協調者依次詢問各個參與者的情況,再決定是進行commit還是roolback。因爲還沒有commit,所以不會導致數據一致性問題。

  • 第三階段協調者和參與者宕機,宕機的這個參與者在掛之前並沒有接收到協調者的指令,或者接收到指令之後還沒來的及做commit或者roolback操作:

    這種情況下,當新的協調者被選出來之後,他同樣是詢問所有的參與者的情況。

    • 只要有機器執行了abort(roolback)操作或者第二階段有參與返回的信息是No的話,那就直接執行roolback操作。
    • 如果有機器執行了commit操作,那麼就直接執行commit操作。

    這樣,當掛掉的參與者恢復之後,只要按照協調者的指示進行事務的commit還是roolback操作就可以了。因爲掛掉的機器並沒有做commit或者roolback操作,而沒有掛掉的機器們和新的協調者又執行了同樣的操作,那麼這種情況不會導致數據不一致現象。

  • 第三階段協調者和參與者宕機,宕機的這個參與者在掛之前已經執行了操作。但是由於他宕機,沒有人知道他執行了什麼操作。

    我們假設掛掉的那臺參與者執行的操作是doCommit。那麼其他沒掛的操作者的狀態要麼是prepare-commit要麼是doCommit。因爲3PC的第三階段一旦有機器執行了doCommit,那必然第一階段大家都是同意doCommit。所以,這時,新選舉出來的協調者一旦發現未掛掉的參與者中有人處於doCommit狀態,那就執行doCommit操作。否則,代表在協調者宕機前,大概率還處於第二階段的狀態,尚未進入到第三階段,就執行rollback操作,直接rollback整個事務。這樣掛掉的參與者恢復之後就能和其他機器保持數據一致性了。前提是要程序具有冪等性。

根據上面的分析我們可以看到:3PC解決了2PC存在的以下問題

單點故障與同步阻塞問題:

由於同時在協調者和參與者中都引入超時機制,在出現單點故障的情況下,參與者們也可以按照策略來進行事務的提交,從而避免長時間的同步堵塞問題。同時,在協調者第三階段超時的情況下,參與者們可以主動commit,也避免了因爲網絡環境而導致共享資源被鎖定。

存在事務狀態不確定的隱患:

通過將2PC的第一階段劃分爲兩個階段,增加了判斷協調者宕機前所在進度的條件,從而避免了事務狀態不確定的情況。但必須要保證程序具有冪等性。

由此,無論是二階段提交還是三階段提交都無法徹底解決分佈式的一致性問題。

總結

根據CAP、BASE原理,在分佈式條件下爲了保證可用性,我們往往採用最終一致性。於是在以上的算法中,都無法解決分佈式的一致性問題,那麼我們需要面對的就是儘量防止出現事務狀態不確定的情況,而對於臨時的數據不一致,一般採用超時重傳的方式,一般網絡條件在少數幾次重傳後便會恢復正常。但是在一些物理性的破壞下會出現長時間的網絡分區,這時候我們需要讓參與者在暫時沒有協調的情況下自行處理事務,採用rollback或commit,以容忍數據不一致來換取共享資源的釋放。

1PC、2PC、3PC算法的採用一般取決於生產環境對數據不一致的容忍程度,越是複雜的算法就越是消耗性能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章