關於分佈式事務的理解(二)

在 關於分佈式事務的理解 一文中,最後留了一個坑是關於TCC框架的。當時因爲時間問題耽擱了,最近總算有時間把這個坑填上了。網絡

本文會大體介紹下兩階段和三階段提交,以及TCC模式。框架


 分佈式事務分爲異步

  1. 兩階段型
  2. 補償型
  3. 異步確保型
  4. 最大努力通知型幾種

上文咱們已近介紹了 異步確保型最大努力通知 這兩種服務模式的具體應用,接下來介紹下剩下兩種。分佈式

兩階段提交(2PC)型


兩階段型:就是分佈式事務兩階段提交,對應技術上的XA、JTA/JTS。post

準備階段

事務協調者(事務管理器)給每一個參與者(資源管理器)發送Prepare消息,每一個參與者要麼直接返回失敗(如權限驗證失敗),要麼在本地執行事務,寫本地的redo和undo日誌,但不提交,到達一種「萬事俱備,只欠東風」的狀態。spa

能夠進一步將準備階段分爲如下三個步驟:日誌

協調者節點向全部參與者節點詢問是否能夠執行提交操做(vote),並開始等待各參與者節點的響應。

參與者節點執行詢問發起爲止的全部事務操做,並將Undo信息和Redo信息寫入日誌。
(注意:若成功這裏其實每一個參與者已經執行了事務操做)

各參與者節點響應協調者節點發起的詢問。若是參與者節點的事務操做實際執行成功,
則它返回一個」贊成」消息;若是參與者節點的事務操做實際執行失敗,則它返回一個」停止」消息。

 提交階段

若是協調者收到了參與者的失敗消息或者超時,直接給每一個參與者發送回滾(Rollback)消息;不然,發送提交(Commit)消息;參與者根據協調者的指令執行提交或者回滾操做,釋放全部事務處理過程當中使用的鎖資源。(注意:必須在最後階段釋放鎖資源)code

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

當協調者節點從全部參與者節點得到的相應消息都爲」贊成」時:接口

1)協調者節點向全部參與者節點發出」正式提交(commit)」的請求。

2)參與者節點正式完成操做,並釋放在整個事務期間內佔用的資源。

3)參與者節點向協調者節點發送」完成」消息。

4)協調者節點受到全部參與者節點反饋的」完成」消息後,完成事務。

 若是任一參與者節點在第一階段返回的響應消息爲」停止」,或者 協調者節點在第一階段的詢問超時以前沒法獲取全部參與者節點的響應消息時:

1)協調者節點向全部參與者節點發出」回滾操做(rollback)」的請求。

2)參與者節點利用以前寫入的Undo信息執行回滾,並釋放在整個事務期間內佔用的資源。

3)參與者節點向協調者節點發送」回滾完成」消息。

4)協調者節點受到全部參與者節點反饋的」回滾完成」消息後,取消事務。

無論最後結果如何,第二階段都會結束當前事務。

二階段提交仍是有幾個缺點的:

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

2、單點故障。因爲協調者的重要性,一旦協調者發生故障。參與者會一直阻塞下去。
尤爲在第二階段,協調者發生故障,那麼全部的參與者還都處於鎖定事務資源的狀態中,而沒法繼續完成事務操做。
(若是是協調者掛掉,能夠從新選舉一個協調者,可是沒法解決由於協調者宕機致使的參與者處於阻塞狀態的問題)

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

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

 三階段提交(3PC)協議


 三階段提交(Three-phase commit),也叫三階段提交協議(Three-phase commit protocol),是二階段提交(2PC)的改進版本。

與兩階段提交不一樣的是,三階段提交有兩個改動點。

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

CanCommit階段

 3PC的CanCommit階段其實和2PC的準備階段很像。協調者向參與者發送commit請求,參與者若是能夠提交就返回Yes響應,不然返回No響應

1.事務詢問 協調者向參與者發送CanCommit請求。詢問是否能夠執行事務提交操做。
而後開始等待參與者的響應。

2.響應反饋 參與者接到CanCommit請求以後,正常狀況下,若是其自身認爲能夠順利執行事務,
則返回Yes響應,並進入預備狀態。不然反饋No

PreCommit階段

協調者根據參與者的反應狀況來決定是否能夠記性事務的PreCommit操做。根據響應狀況,有如下兩種可能。 假如協調者從全部的參與者得到的反饋都是Yes

1.發送預提交請求 協調者向參與者發送PreCommit請求,並進入Prepared階段。

2.事務預提交 參與者接收到PreCommit請求後,會執行事務操做,並將undo和redo信息記錄到事務日誌中。

3.響應反饋 若是參與者成功的執行了事務操做,則返回ACK響應,同時開始等待最終指令。

假若有任何一個參與者向協調者發送了No響應,或者等待超時以後,協調者都沒有接到參與者的響應,那麼就執行事務的中斷。

1.發送中斷請求 協調者向全部參與者發送abort請求。

2.中斷事務 參與者收到來自協調者的abort請求以後(或超時以後,仍未收到協調者的請求),執行事務的中斷。

doCommit階段

執行提交

1.發送提交請求 協調接收到參與者發送的ACK響應,那麼他將從預提交狀態進入到提交狀態。
並向全部參與者發送doCommit請求。

2.事務提交 參與者接收到doCommit請求以後,執行正式的事務提交。並在完成事務提交以後釋放全部事務資源。

3.響應反饋 事務提交完以後,向協調者發送Ack響應。

4.完成事務 協調者接收到全部參與者的ack響應以後,完成事務。

中斷事務 協調者沒有接收到參與者發送的ACK響應(多是接受者發送的不是ACK響應,也可能響應超時),那麼就會執行中斷事務。

1.發送中斷請求 協調者向全部參與者發送abort請求

2.事務回滾 參與者接收到abort請求以後,利用其在階段二記錄的undo信息來執行事務的回滾操做,並在完成回滾以後釋放全部的事務資源。

3.反饋結果 參與者完成事務回滾以後,向協調者發送ACK消息

4.中斷事務 協調者接收到參與者反饋的ACK消息以後,執行事務的中斷。

 

缺點

在doCommit階段,若是參與者沒法及時接收到來自協調者的doCommit或者rebort請求時,會在等待超時以後,
會繼續進行事務的提交。(其實這個應該是基於機率來決定的,當進入第三階段時,
說明參與者在第二階段已經收到了PreCommit請求,那麼協調者產生PreCommit請求的前提條件是他在第二階段開始以前,
收到全部參與者的CanCommit響應都是Yes。(一旦參與者收到了PreCommit,意味他知道你們其實都贊成修改了)
因此,一句話歸納就是,當進入第三階段時,因爲網絡超時等緣由,雖然參與者沒有收到commit或者abort響應,
可是他有理由相信:成功提交的概率很大。 )

 瞭解了2PC和3PC以後,咱們能夠發現,不管是二階段提交仍是三階段提交都沒法完全解決分佈式的一致性問題,這也是爲何咱們提倡用BASE理論去解決分佈式事務的問題。下面咱們介紹下TCC事務方案

 

TCC兩階段補償型


 TCC是Try-Confirm-Cancel的簡稱:

Try階段:

    完成全部業務檢查(一致性),預留業務資源(準隔離性)

    回顧上面航班預約案例的階段1,機票就是業務資源,全部的資源提供者(航空公司)預留都成功,try階段纔算陳宮

Confirm階段:

    確認執行業務操做,不作任何業務檢查, 只使用Try階段預留的業務資源。回顧上面航班預約案例的階段2,美團APP確認兩個航空公司機票都預留成功,所以向兩個航空公司分別發送確認購買的請求。

Cancel階段:

    取消Try階段預留的業務資源。回顧上面航班預約案例的階段2,若是某個業務方的業務資源沒有預留成功,則取消全部業務資源預留請求。

TCC屬於補償型柔性事務,本質也是一個兩階段型事務,這與2PC是極爲類似的,可是與2PC的不一樣點是,2PC屬於資源層事務,而TCC是服務層事務。

 

1) 在階段1:

    在XA中,各個RM準備提交各自的事務分支,事實上就是準備提交資源的更新操做(insert、delete、update等);而在TCC中,是主業務活動請求(try)各個從業務服務預留資源。

2) 在階段2:

    XA根據第一階段每一個RM是否都prepare成功,判斷是要提交仍是回滾。若是都prepare成功,那麼就commit每一個事務分支,反之則rollback每一個事務分支。

    TCC中,若是在第一階段全部業務資源都預留成功,那麼confirm各個從業務服務,不然取消(cancel)全部從業務服務的資源預留請求。

TCC兩階段提交與XA兩階段提交的區別是:

    XA是資源層面的分佈式事務,強一致性,在兩階段提交的整個過程當中,一直會持有資源的鎖。

   TCC是業務層面的分佈式事務,最終一致性,不會一直持有資源的鎖。

     TCC中的兩階段提交併無對開發者徹底屏蔽,也就是說從代碼層面,開發者是能夠感覺到兩階段提交的存在。如上述航班預約案例:在第一階段,航空公司須要提供try接口(機票資源預留)。在第二階段,航空公司提須要提供confirm/cancel接口(確認購買機票/取消預留)。開發者明顯的感知到了兩階段提交過程的存在。try、confirm/cancel在執行過程當中,通常都會開啓各自的本地事務,來保證方法內部業務邏輯的ACID特性。其中:

    一、try過程的本地事務,是保證資源預留的業務邏輯的正確性。

    二、confirm/cancel執行的本地事務邏輯確認/取消預留資源,以保證最終一致性,也就是所謂的補償型事務(Compensation-Based Transactions)。

因爲是多個獨立的本地事務,所以不會對資源一直加鎖。

 

總結 


算是上篇文章,咱們已經總共介紹了三種柔性事務方案

最大努力通知(非可靠消息、按期校對)

可靠消息最終一致性(異步確保型)

TCC(兩階段型、補償型)

  TCC事務方案中又能夠區分出通用型,異步確認型,補償型。具體的應用中該作如何的選擇咱們必須得根據業務來作判斷。通常而言,對於補償行爲較少,一致性要求不高的模式,咱們首推可靠消息的最終一致,例如用戶註冊後的發郵件,對於一致性要求高的,例如訂單交易與庫存,支付系統和帳戶系統,TCC會是一個很好的選擇。

  不管咱們採用任何服務模式,人工介入老是最後的保障。最後再推薦一篇文章關於分佈式服務的選擇

 

[分佈式事務主流解決方案優缺點大pk]

相關文章
相關標籤/搜索