在之前的文章中我們介紹了關于二階段送出協定的設計和實作原理,并且介紹了二階段送出協定在使用過程中的可能存在的問題,例如同步阻塞、協調者單點問題、腦裂等等。是以在二階段送出協定的基礎上行出現了三階段送出協定。下面我們就來詳細介紹一下三階段送出。
三階段送出協定
三階段送出,是Three-Phase Commit的縮寫,是二階段送出的改進版本,是将而階段送出協定的送出事務請求的過程分為了兩部分執行,三階段送出由CanCommit、PreCommit和DoCommit三個階段組成,如下圖所示。
第一階段:CanCommit
1、事務詢問
協調者向所有的參與者發送一個包含事務内容的CanCommit請求,并且詢問是否可以執行送出事務的操作,并且開始等待參與者的響應。
2、各個參與者向協調者回報事務詢問的響應
參與者在收到了來自協調者的CanCommit請求之後,在正常情況下,如果是可以執行事務操作,那麼就會傳回成功,并且進入到準備階段狀态,如果不能執行事務,就會回報失敗。
第二階段:PreCommit
在第二個階段,協調者會根據各個參與者所回報的情況,最終來決定是否執行事務的PreCommit操作,在正常情況下,會有兩種可能的執行結果。
事務執行預送出
假設協調者從所有的參與者中獲得到回報内容都是成功,那麼就會執行事務執行的預送出操作。
1、發送預送出請求
協調者向所有的參與者節點發送PreCommit請求。并且進入到Prepared階段
2、事務預送出
參與者收到了PreCommit請求之後,會執行事務操作,并且将Undo和Redo的資訊記錄到日志資訊中。
3、參與者向協調者回報事務執行情況
如果參與者都成功的執行了事務操作,就會給協調者回報成功的響應,同時會等待最終的送出或者是終止的指令。
中斷事務
假設在任何一個參與者在向協調者回報消息的時候隻要有一個回報了失敗,或者是在等待逾時之後也沒有回報,那麼就會執行事務中斷操作。
1、發送中斷請求
協調者向所有的參與者節點發送中斷請求
2、中斷事務
參與者無論是否收到中斷請求,或者是出現等待逾時的情況,都會中斷自身事務操作。
第三階段:DoCommit
在這個階段開始真正送出事務請求,一般會出現如下的兩種情況
執行送出請求
1、發送送出請求
在進入到這一階段之後,假設協調者處于一個正常的工作狀态,并且接收到了所有的參與者回報的正常請求,這個時候它的狀态就會從預送出轉換為送出,并且向所有的參與者發送DoCommit請求。
2、事務送出
參與者在接收到了DoCommit請求之後,會正式的執行事務的送出操作,并且在送出完成之後釋放資源。
3、回報事務執行結果
參與者在完成事務正常操作之後,回報執行事務的結果給協調者
4、完成事務
協調者在接收到參與者回報的消息之後,完成整個事務的執行。
中斷事務
進入到這個階段,假設協調者是正常的工作狀态,并且有任意的參與者回報失敗的響應,或者是在等待逾時之後也沒有響應,協調者還沒有收到參與者的消息,那麼就會執行事務的中斷。
1、發送中斷事務請求
協調者向所有的參與者發送事務中斷請求
2、事務復原
參與者收到了事務中斷請求之後,會利用Undo的日志來執行事務的復原,并且釋放在復原完成之後的資源
3、回報事務結果
參與者在完成了事務復原之後,向協調者回報消息
4、中斷事務
協調者在接收到所有參與者的回報之後,中斷事務執行。
這裡需要注意的是,在進入到了第三階段之後,與二階段送出的情況類似,會出現兩種故障情況。
第一、協調者出現問題,收不到回報。
第二、協調者和參與者之間的網絡出現故障
無論以上那種情況的出現,都會導緻參與者無法接到來自協調者的DoCommit請求或者是接收不到中斷請求,那麼基于這種情況的發生,一般的操作就是再參與者完成了等待逾時之後,繼續進行事務操作。
優缺點
整體來講,三階段送出相對于二階段送出來講,最大的優勢就是降低了參與者的阻塞範圍,并且在出現了單點故障之後仍然可以達成一緻。
而三階段送出的缺點也是顯然易見,三階段送出協定去除了阻塞的同時引入了新的問題,如果在完成第二階段參與者收到了PreCommit請求之後,如果這個時候出現了網絡分區的情況,協調者存在的節點與參與者所在的節點出現了網絡故障,那麼這個時候,就會出現資料不一緻的情況。