昨天提到在資料庫領域有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以外,就會來將這幾個共識演算法做一個總整理與比較。