2PC
githubgit
在上一篇文章中咱們介紹了本地事務,隨着軟件複雜度的上升,咱們會須要一種能夠在多個數據庫之間完成事務(分佈式事務)的方法,而這個方法也必須可以保證ACID。因而就出現了2PC - Two phase commit protocol。事實上2PC不單單適用於多數據庫事務場景下使用,也適用於全部支持2PC的參與方(Participants)。github
算法介紹
2PC的參與方有:算法
- 一個做爲Coordinator的節點
- 多個做爲Cohort的網絡節點
2PC假設:數據庫
- 全部節點都有一個穩定存儲用以保存WAL(write-ahead log)
- 沒有一個節點會永遠崩潰(即會最終恢復)
- write-ahead log中存儲的數據永遠不會丟失,不會因崩潰而損壞
- 任意兩個節點都可以互相通訊
第四個假設太過嚴格,實際上有不是全部的2PC實現都知足。第1、二個假設則大多數2PC實現都能知足。segmentfault
PS. 若是某個節點徹底損壞(好比服務器物理損毀),那麼數據就直接丟失了。服務器
2PC的執行步驟:網絡
-
Commit request phase /Voting phase。這個階段作:併發
- Coordinator發送一個查詢是否贊成commit的請求到全部Cohort,而且等待全部Cohort給出應答。
- Cohort收到請求,開始執行事務,執行到就差commit爲止(不commit)。
- 每一個Cohort根據操做結果返回Yes或No
-
Commit phase / Completion phase。這個階段分兩種狀況:分佈式
-
成功。全部Cohort應答Yeside
- Coordinator發送commit指令到全部Cohort
- 每一個Cohort執行commit,併發送ack到Coordinator
- 當Coordinator收到每一個Cohort的ack以後則事務完成
-
失敗。任意Cohort應答No,或者在commit request階段超時
- Coordinator發送rollback指令到全部Cohort
- 每一個Cohort執行rollback,併發送ack到Coordinator
- 當Coordinator收到每一個Cohort的ack以後則事務撤銷
消息流(摘自wiki):
Coordinator Cohort
QUERY TO COMMIT
-------------------------------->
VOTE YES/NO prepare*/abort*
<-------------------------------
commit*/abort* COMMIT/ROLLBACK
-------------------------------->
ACKNOWLEDGMENT commit*/abort*
<--------------------------------
end
2PC的通訊次數是:
- 若是實現沒有要求任意兩個Cohort能夠通訊,那麼是2n(n=Cohort數量)
- 若是實現要求任意兩個Cohort能夠通訊,那麼是n^2
異常處理
咱們把上面的流程簡化以便說明異常處理:
- Coordinator發送query to commit
- Cohort執行prepare
- Cohort返回ack
- Coordinator發送commit/rollback
- Cohort執行commit/rollback
- Cohort返回ack
從Coordinate角度來看出現異常要怎麼處理:
- step 1發生異常,Coordinator須要執行rollback
- step 二、3發生異常,意味着Coordinator沒有收到Cohort的響應,這個時候因認定爲失敗,執行rollback
- step 4發生異常,Coordinator重試commit/rollback
- step 五、6發生異常,意味着Coordinator沒有收到Cohort的響應,這個時候因認定爲失敗,重試commit/rollback
從Cohort角度來看看看出現異常怎麼處理:
- step 1,意味着Cohort沒有收到請求,什麼都不須要作
- step 2,意味着Cohort沒有執行成功,什麼都不須要作
- step 3,意味着Coordinator沒有收到結果,什麼都不須要作,等待Coordinator重試便可。Cohort要保證prepare是冪等的。
- step 4,等待Coordinator重試便可,這裏有點tricky,若是Coordinator遲遲不retry,那麼Cohort要自行rollback,不然就會形成資源死鎖。
- step 5,等待Coordinator重試便可
- step 6,意味着Coordinator沒有收到結果,什麼都不須要作,等待Coordinator重試便可,Cohort要保證commit/rollback是冪等的。
觀察一下你就會發現依然存在漏洞——會出現違反一致性的狀況:
- 若Coordinator/Cohort因崩潰遺失了信息,有的Cohort已commit,有的Cohort則恢復到commit以前的狀態。
- 若Coordinator在step 4發送commit,而Cohort在rollback(因timeout致使的rollback)。
出現上面的狀況就須要人工介入了。
更多2PC的異常處理推理詳見這篇slides。
缺點
根據上面的算法介紹能夠看出2PC是一個阻塞協議:
- 若是兩個事務針對同一個數據,那麼後面的要等待前面完成,這是因爲Cohort採用的是本地事務所決定的
- Cohort在commit request phase以後會阻塞,直到進入Coordinator告之Cohort進入commit phase
對於ACID的保證
2PC所保證的ACID和本地事務所提到的ACID不太同樣——事實上對於全部分佈式事務來講都不太同樣:
- A,正常狀況下保證
- C,在某個時間點,會出現A庫和B庫的數據違反一致性要求的狀況
- I,在某個時間點,A事務可以讀到B事務部分提交的結果
- D,和本地事務同樣,只要commit則數據被持久
XA
XA是一個針對分佈式事務的spec,它實現了2PC協議。在XA中定義了兩種參與方:Transaction Manager(TM)和Resource Manager(RM),其中TM=2PC中的Coordinator,RM=2PC中的Cohort。
Java規範中的JTA(Java Transaction API)定義了XA的Java接口,JTA的實現有Bitronix、Atomikos等等。
參考資料