深入理解兩階段提交協議
兩階段提交協議(two phase commit protocol,以下簡稱2PC協議)作為最簡單原子提交協議,在很多需要使用分布式事務的場景中會經常用到。下面將嘗試深入而簡單的闡釋2PC協議,並給出一個簡單的demo實現。
2PC協議中的兩種角色
2PC協議中存在著一個協調者(Coordinator)和多個參與者(Participant)。協調者負責接收參與者發起的事務請求,向所有參與者發起投票,收集投票結果,做出Commit或者Abort決定,並將決定通知給參與者。參與者負責監聽來自協調者的投票請求,以及最後的決定。一旦協調者的決定是Abort,所有參與者都必須回滾本地事務,否則所有參與者都提交本地事務。
2PC協議的一般過程
假設各個環節沒有異常和失敗,典型的2PC協議過程是這樣的。
- 協調者給所有的參與者發送投票請求。
- 參與者收到投票請求,會給協調者回復YES或者NO。如果回復NO, 那該參與者決定Abort,並結束流程。
- 協調者收集齊所有參與者的投票,如果所有參與者都投YES,並且協調者本身投YES,那協調者將決定Commit,並將Commit消息發送給所有參與者。否則,協調者決定Abort,並將Abort消息發送給所有投YES票的參與者(投NO票的參與者在第2步時已經中止,不用通知)。協調者結束流程。
- 每個投YES票的參與者等待協調者的Commit或者Abort消息。當收到消息時,依據消息做出決定,然後結束流程。
其中1、2步是投票階段,3、4步是決定階段。
異常處理
所有分布式系統都必須能夠處理網絡中斷、超時或系統故障等等異常情況,2PC協議也不例外。因此,這裏將逐步分析2PC協議各個階段可能會出現的異常,以及可用的處理方式。
第1階段
協調者給參與者發送投票請求,有可能發送的過程中協調者系統故障。故障恢復以後,協調者需要能夠決定故障前正在請求的事務的狀態。為了應對這種情況下,需要在協調者開始給參與者發送投票請求之前,記錄狀態為start2PC。這樣在故障恢復以後,通過查看狀態記錄,協調者知道當時的事務投票請求發送時出現了故障,於是可以直接決定Abort,並記錄狀態Abort。
如果發送投票過程中,參與者故障或者參與者與協調者網絡超時或中斷,導致發送失敗,都視為投票失敗,協調者可直接直接決定Abort,並記錄狀態Abort。
第2階段
參與者在投票之後,到收到協調者回復之前,這段時間對事務的最終狀態是不確定的。如果由於某種原因,沒有收到協調者的回復,該參與者必須通過向協調者或其他參與者咨詢來確定最終決定,這個過程叫cooperative termination。
參與者收到請求,如果投票YES, 需要先記錄狀態YES, 然後再回復YES協調者。這樣,如果參與者在發送請求之後掛掉,通過查看狀態記錄,知道自己投了YES,但最終決定還需要向協調者或者其他參與者咨詢。如果得知最後的決定是Commit,此時參與者就提交本地事務,並記錄狀態為Commit;如果最後的決定是Abort,參與者就回滾本地事務,並記錄狀態為Abort。
如果參與者投票NO,情況就比較簡單,直接記錄Abort即可。
第3階段
協調者在等待參與者回復的時候,可能由於參與者系統故障、網絡中斷或超時,導致沒有收到回復。此時協調者直接決定Abort, 記錄Abort狀態,並把決定發送給參與者。而故障恢復之後的參與者可自己向協調者查詢事務決定,然後根據決定處理本地事務。
協調者收到參與者回復之後,如果決定Commit,則先記錄狀態Commit,然後發送Commit消息給所有參與者。這樣,如果協調者在記錄Commit狀態之前故障,那恢復之後,通過檢查會發現狀態是start2PC,協調者可以直接決定Abort;如果協調者在記錄Commit狀態之後故障,此時可能已通知部分參與者,等到故障恢復時,未收到Commit通知的參與者可咨詢協調者最終的決定。
第4階段
參與者在等待協調者決定的時候,可能出現故障,也可能協調者的消息由於網絡原因沒能送達。這種情況下,參與者可在故障恢復後或者超時後咨詢協調者或者其他參與者,獲取最終的決定。
歷史記錄的刪除
如果2PC協議中的參與者或者協調者要刪除事務的歷史記錄,必須滿足以下幾個條件,才能保證事務刪除之後對其他參與者的事務最終狀態的確定不產生影響。
- 必須保證本地刪除的記錄是最終狀態(Commit或者Abort狀態)。
- 必須保證刪除的事務在其他參與者那也是最終狀態。
第一條是為了保障所有未做出決定的事務不會被刪除,因為可能會在下次故障恢復中做出決定;第二條是為了保證如果有參與者的本地事務不是最終狀態,通過咨詢協調者或者其他參與者,可以得到該事務的最終狀態。
在實際操作中,可以采取這樣的策略:參與者刪除記錄時,只考慮第1條,而協調者同時考慮1、2兩條,這樣協調者可以保證如果有事務的狀態不是最終狀態,找它就可以確定。
Demo實現
我實現了一個2PC協議的demo項目:https://github.com/segeon/2pc。該demo除了沒實現歷史記錄刪除的約束外,其余的協議要求和異常處理都已實現。
參考資料
http://research.microsoft.com/en-us/people/philbe/chapter7.pdf
深入理解兩階段提交協議