分布式系统原理 之6 两阶段提交协议
分布式系統原理
兩階段提交協議
兩階段提交協議是一種經典的強一致性中心化副本控制協議[2][3]。雖然在工程中該協議有較多的問題,但研究該協議能很好的理解分布式系統的幾個典型問題。
1. 問題背景
兩階段提交(two phase commit)協議是一種歷史悠久的分布式控制協議。最早用于在分布式數據庫中,實現分布式事務。這里有必要首先簡單介紹一下兩階段提交的最初問題背景,從而能更好的理解該協議。
在經典的分布式數據庫模型中,同一個數據庫的各個副本運行在不同的節點上,每個副本的數據要求完全一致。數據庫中的操作都是事務(transaction),一個事務是一系列讀、寫操作,事務滿足ACID。每個事務的最終狀態要么是提交(commit),要么是失敗(abort)。一旦一個事務成功提交,那么這個事務中所有的寫操作中成功,否則所有的寫操作都失敗。在單機上,事務靠日志技術或 MVCC等技術實現。在分布式數據庫中,需要有一種控制協議,使得事務要么在所有的副本上都提交,要么在所有的副本上都失敗。對同一個事務而言,雖然在所有副本上執行的事務操作都完全一樣,但可能在某些副本上可以提交,在某些副本上不能提交。這是因為,在某些副本上,其他的事務可能與本事務有沖突(例如死鎖),從而造成在有些副本上事務可以提交,而有些副本上事務無法提交。本文不再深入討論事務沖突的問題,只是將問題背景介紹情況,該類問題可以通過閱讀經典的數據
庫系統相關資料了解。
2. 流程描述
按本文的分類,兩階段提交協議是一種典型的“中心化副本控制”協議。在該協議中,參與的節點分為兩類:一個中心化協調者節點(coordinator)和 N 個參與者節點(participant)。每個參與者節點即上文背景介紹中的管理數據庫副本的節點。
兩階段提交的思路比較簡單,在第一階段,協調者詢問所有的參與者是否可以提交事務(請參與者投票),所有參與者向協調者投票。在第二階段,協調者根據所有參與者的投票結果做出是否事務可以全局提交的決定,并通知所有的參與者執行該決定。在一個兩階段提交流程中,參與者不能改變自己的投票結果。兩階段提交協議的可以全局提交的前提是所有的參與者都同意提交事務,只要有一個參與者投票選擇放棄(abort)事務,則事務必須被放棄。
協議流程如下:
流程 2.6.1:兩階段提交協調者流程 1. 寫本地日志“begin_commit”, 并進入 WAIT 狀態; 2. 向所有參與者發送“prepare 消息”; 3. 等待并接收參與者發送的對“prepare 消息”的響應;3.1 若收到任何一個參與者發送的“vote-abort 消息”;3.1.1 寫本地“global-abort”日志,進入 ABORT;3.1.2 向所有的參與者發送“global-abort 消息”;3.1.3 進入 ABORT 狀態;3.2 若收到所有參與者發送的“vote-commit”消息;3.2.1 寫本地“global-commit”日志,進入 COMMIT 狀態;3.2.2 向所有的參與者發送“global-commit 消息”; 4. 等待并接收參與者發送的對“global-abort 消息”或“global-commit 消息”的確認響應消息, 一旦收到所有參與者的確認消息,寫本地“end_transaction” 日志流程結束。 流程 2.6.2:兩階段提交協調者流程 1.寫本地日志“init”記錄,進入 INIT 狀態 2.等待并接受協調者發送的“prepare 消息”,收到后2.1 若參與者可以提交本次事務2.1.1 寫本地日志“ready”,進入 READY 狀態2.1.2 向協調者發送“vote-commit”消息2.1.4 等待協調者的消息2.1.4.1 若收到協調者的“global-abort”消息2.1.4.1.1 寫本地日志“abort”,進入 ABORT 狀態2.1.4.1.2 向協調者發送對“global-abort”的確認消息2.1.4.2 若收到協調者的“global-commit”消息2.1.4.1.1 寫本地日志“commit”,進入 COMMIT 狀態2.1.4.1.2 向協調者發送對“global-commit”的確認消息2.2 若參與者無法提交本次事務2.2.1 寫本地日志“abort”,進入 ABORT 狀態2.2.2 向協調者發送“vote-abort”消息2.2.3 流程對該參與者結束2.2.4 若后續收到協調者的“global-abort”消息可以響應 3. 即使流程結束,但任何時候收到協調者發送的“global-abort”消息或“global-commit”消息 也都要發送一個對應的確認消息。3. 異常處理
3.1 宕機恢復
兩階段提交協議中,使用了日志技術從而在宕機后可以恢復流程狀態。這里簡單分析一下兩階段提交試用日志做宕機恢復的過程。
3.1.1 協調者宕機恢復
協調者宕機恢復后,首先通過日志查找到宕機前的狀態。
如果日志中最后是“begin_commit”記錄,說明宕機前協調者處于 WAIT 狀態,協調者可能已經發送過“prepare 消息”也可能還沒發送,但協調者一定還沒有發送過“global-commit 消息”或“global-abort 消息”,即事務的全局狀態還沒有確定。此時,協調者可以重新發送“prepare 消息”繼續兩階段提交流程,即使參與者已經發送過對“prepare 消息”的響應,也不過是再次重傳之前的
響應而不會影響協議的一致性。
如果日志中最后是“global-commit”或“global-abort”記錄,說明宕機前協調者處于 COMMIT或 ABORT 狀態。此時協調者只需重新向所有的參與者發送“global-commit 消息”或“global-abort消息”就可以繼續兩階段提交流程。
3.1.2 參與者宕機恢復
參與者宕機恢復后,首先通過日志查找宕機前的狀態。
如果日志中最后是“init”記錄,說明參與者處于 INIT 狀態,還沒有對本次事務做出投票選擇,參與者可以繼續流程等待協調者發送的“prepare 消息”。
如果日志中最后是“ready”記錄,說明參與者處于 REDAY狀態,此時說明參與者已經就本次事務做出了投票選擇,但宕機前參與者是否已經向協調者發送“vote-commit”消息并不可知。所以此時參與者可以向協調者重發“vote-commit”,并繼續協議流程。
如果日志中最后是“commit”或“abort”記錄,說明參與者已經收到過協調者的“global-commit消息”(處于 COMMIT 狀態)或者“global-abort 消息”(處于 ABORT 狀態)。至于是否向協調者發送過對“global-commit”或“global-abort”的確認消息則未知。但即使沒有發送過確認消息,由于協調者會不斷重發“global-commit”或“global-abort”,只需在收到這些消息時發送確認消息既可,不影響協議的全局一致性。
3.2 響應超時
協議主要的異常最終會體現在流程中“等待消息”超時上,即等待了一個足量長的時間后,不能接收到需要的消息,使得流程無法進行下去。下面逐一分析這些超時的原因和對協議的影響。
3.2.1 協調者在 WAIT 狀態超時
協調者在 WAIT 狀態狀態超時,即協調者等待參與者對“prepare 消息”的響應超時,在超時時間內始終不能收到所有的參與者的投票結果而收到的響應都是“vote-commit”消息,從而協調者無法確定該事務是否可以提交。這種超時可能的原因有:
對于這種超時,協調者可以選擇直接放棄整個事務,向所有參與者發送“global-abort”消息,進入 ABORT 狀態。由于協調者在超時前并沒有發送任何“global-abort”或者“global-commit”消息,所以協調者此時放棄事務不影響協議的一致性。
3.2.2 協調者在 COMMIT 或 ABORT 狀態超時
協調者在COMMIT或ABORT狀態超時,即協調者等待參與者對“global-commit”或“global-abort”消息的響應時超時,從而協調者無法確認兩階段提交是否完成。這種超時可能的原因有:
對于這種超時,協調者只能不斷重發“global-commit” 或“global-abort”消息給尚未響應的參與者,直到所有的參與者都發送響應。可以這么認為,兩階段提交協議對于這種超時的相關異常沒有很好的容錯機制,整個流程只能阻塞在這里,且流程狀態處于未知。也許所有的參與者都完成了各自的流程,只是由于協調者無法收到響應,整個兩階段提交協議就無法完成。
3.2.3 參與者在 INIT 狀態超時
參與者等待協調者的“prepare”消息時超時,此種異常的原因可能是協調者宕機或者協調者與參與者網絡中斷。對于這種超時,參與者可以進入 ABORT 狀態,這樣即使后續收到了“prepare”消息,也不影響協議的一致性也不會阻塞其他流程,唯一的缺點是,該事務可能原本可以提交,現在卻被放棄。
3.2.4 參與者在 READY 狀態超時
參與者在 READY 狀態等待協調者發送的“global-commit”或“global-abort”消息超時。出現這種超時的原因可能是協調者宕機也可能是網絡中斷。
因為參與者處于 READY狀態,說明參與者之前一定已經發送了“vote-commit”消息,從而參與者已經不能改變自己的投票選擇。此時,參與者只能不斷重發“vote-commit”消息,直到收到協調者的“global-commit”或“global-abort”消息后流程才可繼續。可以這么認為,兩階段提交協議對于這種超時的相關異常也沒有很好的容錯機制,整個流程只能阻塞在這里,且對于參與者而言流程狀態處于未知,參與者即不能提交本地節點上的事務,也不能放棄本地節點事務。
4. 協議分析
兩階段提交協議在工程實踐中真正使用的較少,主要原因有以下幾點:
第一、兩階段提交協議的容錯能力較差。從上文的分析可以看出,兩階段提交協議在某些情況下存在流程無法執行下去的情況,且也無法判斷流程狀態。在工程中好的分布式協議往往總是可以在即使發生異常的情況下也能執行下去。例如,回憶 Lease 機制(2.3 ),一旦 lease 發出,無論出現任何異常,Lease 服務器節點總是可以通過時間判定出 Lease 是否有效,也可以用等待 Lease 超時的方法收回 Lease 權限,整個 Lease 協議的流程不存在任何流程被阻塞而無法執行下去的情況。與Lease 機制的簡單有效相比,兩階段提交的協議顯得較為復雜且容錯能力差。
第二、兩階段提交協議的性能較差。一次成功的兩階段提交協議流程中,協調者與每個參與者之間至少需要兩輪交互 4 個消息“prepare”、 “vote-commit”、 “global-commit”、 “確認 global-commit”。過多的交互次數會降低性能。另一方面,協調者需要等待所有的參與者的投票結果,一旦存在較慢的參與者,會影響全局流程執行速度。
雖然存在一些改進的兩階段提交協議可以提高容錯能力和性能,然而這類協議依舊是在工程中使用較少的一類協議,其理論價值大于實踐意義。
參考:《分布式系統原理介紹》 - 劉杰
總結
以上是生活随笔為你收集整理的分布式系统原理 之6 两阶段提交协议的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 分布式系统原理 之5 日志技术
- 下一篇: 分布式系统原理 之7 基于MVCC的分布