昨天提到在資料庫領域有2PC來解決Distributed Transaction ACID的問題。但是最大的缺點便是單一Coordinator,如果失效那麼Participants便會block住。
因此今天要介紹的就是進化版3 Phase Commitment,簡稱3PC。
最大的差異便是比起2PC多了一個Phase(廢話)。
直接用最常見的流程圖說明:
角色一樣分成兩個,流程分成三個Phase
。另外,3PC這邊把Participants改成Cohorts
Phase1
canCommit
的訊息給所有的Cohorts,canCommit
,如果可以執行transaction,資料沒有被lock住,便回覆 Yes
。否則回覆No
並且abortPhase2
No
或是發生Timeout
,宣告 Distributed Transaction 失敗,並且發送 abort
給所有的Cohorts
preCommit
給所有的Cohorts
abort
或是Coordinator斷線或是掉封包導致Timeout
,abort。preCommit
,執行transaction在副本資料上,並且回傳ACK
訊息回去並且等待最終的commitPhase3
ACK
,就發送doCommit
訊息。否則有任一個Cohorts Timeout
,一樣宣告 Distributed Transaction 失敗。doCommit
,將更新過後的資料副本轉為最新的資料。並且回覆haveCommitted
。最大的問題並不是演算法本身有什麼問題,而是兩者的容錯能力!
因為兩者皆是要達到Strong Consistency的標準,因此必須考慮執行的過程中是否有任一個server故障失效,並且在此情境下仍然保持一致。
所以重點在於2PC與3PC在有故障失效的情境下,是否有辦法仍然保持資料一致,要不全都commit否則就全都rollback。
如果再回去看一次2PC的流程會發現,有幾個會出問題的地方
Coordinator失效,而Participants都正常
重新選出一個Coordinator,並且根據目前的phase,與其餘Participants目前transaction執行狀況,重新決定是Commit還是Rollback,不會有不一致的情況。
某個Participant失效,Coordinator仍然正常運作
這種情況可能發生在phase2
發送完commit後,Participant還沒執行commit失效。但是因為Coordinator還活著,因此當Participant回復後,仍然可以跟Coordinator訊問上一個動作,而與其他的Participant執行一樣的Commit或是Rollback
某個Participant與Coordinator都失效
發生在phase1
還沒問題,因為大家都還沒真的Commit或是Rollback,重新選一個Coordinator仍然是一致的。
問題發生在phase2
,如果失效的Participant已經執行了Commit或是Rollback其中一個,但是因為他跟Coordinator都失效了,剩下的所有人沒人知道發生什麼事。重新選出一個Coordinator後執行的動作可能跟失效的Participant執行的動作是不一樣的,在這個情況下,數據是有機會不一致的!
3PC在加入一個新的preCommit phase
後我們來看看情境3會怎麼發展。
如果失效的Participant已經執行了Commit,表示什麼?
表示在phase2大家都已經收到了preCommit
,只是在phase3
有人執行了commit有人還沒,而此時Coordinator失效。
這種情況,新選出來的Coordinator仍然可以執行commit,因為他從phase2
再詢問一次大家的狀況仍然會是ACK
,只要重新進入phase3
,再發送commit
訊息給大家即可。
如果Participant已經執行了Rollback,則新選出來的Coordinator再從phase2
再詢問一次大家,一定也會得到同樣的Rollback結果,從而使得最終結果仍然一致。
3PC的缺點也非常顯而易見,為了確保Strong Consistency與某些節點故障的問題,增加了許多條件與步驟,導致時做起來非常繁瑣。
接下來的文章除了介紹Raft以外,就會來將這幾個共識演算法做一個總整理與比較。