前言
如果在分布式系統中發起一個事務,該事務涉及到多個不同節點,那么為了保證事務ACID特性,就需要引入一個協調者來統一調度事務涉及的多個節點,被調度的節點稱為事務參與者,由此衍生出了 2PC 和 3PC 協議,本文主要主要介紹這兩個協議,
2PC
2PC(Two-Phase Commit)兩階段提交,是不是想到了 MySQL 的2PC,MySQL 的2PC 是為了保證單個資料庫事務的完整性,讓每次執行寫操作時 redo_log 和 binlog 兩個檔案的一致性,
分布式事務的2PC協議也是一樣,為了保證分布式事務的一致性,它分為兩個階段:Prepare 和 Commit
Prepare
Prepare 提交事務請求階段:
1、協調者向所有參與者發起事務請求,詢問是否可執行事務操作,然后等待各個參與者的回應
2、各參與者接收到協調者事務請求后,執行事務操作,并將資訊記錄到事務日志中
3、如果參與者成功執行了事務并寫入日志資訊,則向協調者回傳 Yes 回應,否則回傳 NO 回應,當然,參與者也可能宕機,不回傳回應
Commit
Commit 執行事務提交階段,分為兩個情況:正常提交和回退,
1、協調者向所有參與者發送 Commit 請求
2、參與者收到 Commit 請求后,執行事務提交,提交完成后釋放事務執行期占用的所有資源
3、參與者執行事務提交后向協調者發送 ACK 回應
4、接收到所有參與者的 ACK 回應后,完成事務提交
中斷事務
在執行 Prepare 階段程序中,如果某些參與者執行事務失敗,宕機或協調者之間的網路中斷,那么協調者就無法收到所有參與者的 Yes 回應,或者某個參與者回傳了 No 回應,此時,協調者就會進入回退流程,對事務進行回退,
注:只要協調者沒有收到所有參與者的 Yes 回應,就會發起事務中斷請求,
1、協調者向所有參與者發送 rollback 請求
2、參與者收到 rollback 后,使用 Prepare 階段的 undo 日志執行事務回滾,完成后釋放事務執行期間占用的所有資源
3、參與者執行事務回滾后向協調者發送 ACK 回應
4、接收到所有參與者的ACK回應后,完成事務中斷
2PC 存在的問題
1、參與者在等待協調者的指令時,其實就是在等待其他參與者的回應,在此程序中,參與者是無法進行其他操作的,也就是阻塞了其運行,如果參與者與協調者之間網路例外導致參與者一直收不到協調者資訊,那么會導致參與者一直阻塞下去
2、在 2PC 中,一切請求都來自協調者,如果協調者宕機,那么就會使參與者一直阻塞并一直占用事務資源
如果協調者也是分布式,使用選主方式提供服務,那么在一個協調者掛掉后,可以選取另一個協調者繼續后續的服務,可以解決單點問題,但是,新協調者無法知道上一個事務的全部狀態資訊(例如已等待 Prepare 回應的時長等),所以也無法順利處理上一個事務,
3PC
上述中說明了 2PC 協議存在的問題,那么 3PC 就是在 2PC 的基礎上,為了解決 2PC 的某些缺點而設計的,3PC 分為三個階段:CanCommit,PreCommit,DoCommit
CanCommit
1、協調者向所有參與者發送事務 canCommit 請求,請求中包含事務內容,詢問是否可以執行事務提交操作,并開始等待回應
2、參與者收到 canCommit 請求后,分析事務內容,判斷自身是否可以執行事務,如果可以,那么就回傳 Yes 回應,進入預備狀態,否則回傳 No 回應
注:此階段參與者并沒有執行事務,而 2PC 的 prepare 階段中參與者是執行了事務的
PreCommit
PreCommit 階段根據各參與者回傳的 canCommit 回應,決定下一步動作,如果收到了所有參與者的 Yes 回應,則執行事務預提交,否則執行事務中斷
預提交階段
1、協調者發送 PreCommit 請求,并進入 Prepared 階段
2、參與者收到 PreCommit 請求后,執行事務操作,并將 undo 和 redo 資訊記錄到事務日志中
3、如果參與者成功執行了事務并寫入 undo 和 redo 資訊,那么反饋 ACK 給協調者,并等待下一步指令
事務中斷
如果 canCommit 階段協調者沒有收到所有參與者的 Yes 回應,協調者就發起 Abort 請求,
1、協調者向所有參與者發送 Abort 請求
2、參與者收到 Abort 請求后,會觸發事務中斷,此外,如果參與者在等待協調者指令超時,會自己觸發事務中斷,在 2PC 中,參與者會一直阻塞的等待協調者指令,所以 3PC 中解決了因為這種情況帶來的阻塞
doCommit
協調者根據 PreCommit 階段參與者的回應決定最終操作,如果協調者收到了所有參與者在 PreCommit 階段的 ACK 回應,那么會進入執行事務提交階段,否則執行事務中斷
事務提交
1、協調者收到所有參與者的 PreCommit 階段的 ACK 回應后,向所有參與者發送 doCommit 請求,并進入提交狀態
2、參與者收到 Commit 請求后,執行事務提交,提交完成后釋放事務執行期間占用的所有資源
3、參與者完成事務提交之后,向協調者回傳 ACK 回應
4、協調者收到所有參與者的 ACK 回應后,完成事務
事務中斷
1、協調者向所有參與者發送 Abort 請求
2、參與者收到 Abort 請求后,會使用 PreCommit 階段記錄的 Undo 資訊進行事務回滾,并在完成回滾后釋放所有事務資源,
注:因為 canCommit 階段并沒有執行事務,所以在 PreCommit 階段執行事務中斷,是不需要事務回滾的,也就不需要回滾后的反饋結果,直接中斷事務即可
3、參與者執行事務回滾后向協調者發送 ACK 回應
4、協調者接收到所有參與者反饋的 ACK 回應后,完成事務中斷
3PC 的改進與不足
改進
1、降低了阻塞
- 參與者回傳 canCommit 請求的回應后,等待 PreCommit 階段的指令,若等待超時,則自動 Abort,降低了阻塞
- 參與者回傳 PreCommit 階段的請求回應后,等待第三階段指令,若等待超時,則自動 commit 事務,也降低了阻塞
2、解決單點故障問題
- 參與者回傳 canCommit 請求回應后,等待 PreCommit 階段指令,若協調者宕機,等待超時后參與者自動 Abort
- 參與者回傳 PreCommit 請求回應后,等待 doCommit 階段指令,若協調者宕機,等待超時后自動 commit 事務
不足
資料的不一致問題仍然可能存在,比如 doCommit 階段協調者發出了 Abort 請求,然后有些參與者沒有收到 Abort,那么就會自動 commit,造成資料不一致,
小結
2PC 和 3PC 都無法完美解決分布式資料一致性問題,雖然無法保證事務ACID特性,但解決問題的思想在很多實際架構中有著廣泛應用,
Paxos 是 Google 大神提出的解決分布式一致性的演算法,后續文章會介紹到,
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/301109.html
標籤:其他
