分散式系統原理(7)兩階段提交協議
兩階段提交協議
問題背景
兩階段提交(two phase commit)協議是一種歷史悠久的分散式控制協議。最早用於在分散式資料庫中,實現分散式事務。這裡有必要首先簡單介紹一下兩階段提交的最初問題背景,從而能更好的理解該協議
在經典的分散式資料庫模型中,同一個資料庫的各個副本執行在不同的節點上,每個副本的資料要求完全一致。資料庫中的操作都是事務(transaction),一個事務是一系列讀、寫操作,事務滿足ACID。每個事務的最終狀態要麼是提交(commit),要麼是失敗(abort)。一旦一個事務成功提交,那麼這個事務中所有的寫操作中成功,否則所有的寫操作都失敗。在單機上,事務靠日誌技術或 MVCC等技術實現。在分散式資料庫中,需要有一種控制協議,使得事務要麼在所有的副本上都提交,要麼在所有的副本上都失敗。對同一個事務而言,雖然在所有副本上執行的事務操作都完全一樣,但可能在某些副本上可以提交,在某些副本上不能提交。這是因為,在某些副本上,其他的事務可能與本事務有衝突(例如死鎖),從而造成在有些副本上事務可以提交,而有些副本上事務無法提交。本文不再深入討論事務衝突的問題,只是將問題背景介紹情況,該類問題可以通過閱讀經典的資料庫系統相關資料瞭解
流程描述
按本文的分類,兩階段提交協議是一種典型的“中心化副本控制”協議。在該協議中,參與的節點分為兩類:一箇中心化協調者節點(coordinator)和 N 個參與者節點(participant)。每個參與者節點即上文背景介紹中的管理資料庫副本的節點
兩階段提交的思路比較簡單,在第一階段,協調者詢問所有的參與者是否可以提交事務(請參與者投票) , 所有參與者向協調者投票。在第二階段,協調者根據所有參與者的投票結果做出是否事務可以全域性提交的決定,並通知所有的參與者執行該決定。在一個兩階段提交流程中,參與者不能改變自己的投票結果。兩階段提交協議的可以全域性提交的前提是所有的參與者都同意提交事務,只要有一個參與者投票選擇放棄(abort)事務,則事務必須被放棄
兩階段提交協調者流程:
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.1.2 向所有的參與者傳送“global-commit 訊息” 4. 等待並接收參與者傳送的對“global-abort 訊息”或“global-commit 訊息”的確認響應訊息,一旦收到所有參與者的確認訊息,寫本地“end_transaction” 日誌流程結束
兩階段提交參與者流程:
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”訊息也都要傳送一個對應的確認訊息
異常處理
宕機恢復
兩階段提交協議中,使用了日誌技術從而在宕機後可以恢復流程狀態。這裡簡單分析一下兩階段提交試用日誌做宕機恢復的過程
協調者宕機恢復
如果日誌中最後是“begin_commit”記錄,說明宕機前協調者處於 WAIT 狀態,協調者可能已經發送過“prepare 訊息”也可能還沒傳送,但協調者一定還沒有傳送過“global-commit 訊息”或“global-abort 訊息”,即事務的全域性狀態還沒有確定。此時,協調者可以重新發送“prepare 訊息”繼續兩階段提交流程,即使參與者已經發送過對“prepare 訊息”的響應,也不過是再次重傳之前的響應而不會影響協議的一致性。
如果日誌中最後是“global-commit”或“global-abort”記錄,說明宕機前協調者處於 COMMIT或 ABORT 狀態。此時協調者只需重新向所有的參與者傳送“global-commit 訊息”或“global-abort訊息”就可以繼續兩階段提交流程
參與者宕機恢復
如果日誌中最後是“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” ,只需在收到這些訊息時傳送確認訊息既可,不影響協議的全域性一致性
響應超時
協議主要的異常最終會體現在流程中“等待訊息”超時上,即等待了一個足量長的時間後,不能接收到需要的訊息,使得流程無法進行下去。下面逐一分析這些超時的原因和對協議的影響
協調者在 WAIT 狀態超時
協調者在 WAIT 狀態狀態超時,即協調者等待參與者對“prepare 訊息”的響應超時,在超時時間內始終不能收到所有的參與者的投票結果而收到的響應都是“vote-commit”訊息,從而協調者無法確定該事務是否可以提交。這種超時可能的原因有:
- 協調者與某個參與者網路中斷,協調者的“prepare”訊息無法傳送到參與者,或者參與者的響應訊息無法傳送到協調者。
- 參與者宕機,如果某個參與者宕機,則無法響應協調者的“prepare 訊息”,只有等該參與者恢復後才能響應訊息。
對於這種超時,協調者可以選擇直接放棄整個事務,向所有參與者傳送“global-abort”訊息,
進入 ABORT 狀態。由於協調者在超時前並沒有傳送任何“global-abort”或者“global-commit”訊息,
所以協調者此時放棄事務不影響協議的一致性
協調者在 COMMIT 或 ABORT 狀態超時
協調者在 COMMIT 或 ABORT 狀態超時,即協調者等待參與者對“global-commit”或“global-abort”訊息的響應時超時,從而協調者無法確認兩階段提交是否完成。這種超時可能的原因有:
- 協調者與某個參與者網路中斷,協調者的“global-commit” 或“global-abort”訊息無法傳送到參與者,或者參與者的響應訊息無法傳送到協調者。
- 參與者宕機,如果某個參與者宕機,則無法響應協調者的“global-commit” 或“global-abort”,只有等該參與者恢復後才能響應訊息。
對於這種超時,協調者只能不斷重發“global-commit” 或“global-abort”訊息給尚未響應的參與者,直到所有的參與者都發送響應。可以這麼認為,兩階段提交協議對於這種超時的相關異常沒有很好的容錯機制,整個流程只能阻塞在這裡,且流程狀態處於未知。也許所有的參與者都完成了各自的流程,只是由於協調者無法收到響應,整個兩階段提交協議就無法完成
參與者在 INIT 狀態超時
參與者等待協調者的“prepare”訊息時超時,此種異常的原因可能是協調者宕機或者協調者與參與者網路中斷。對於這種超時,參與者可以進入 ABORT 狀態,這樣即使後續收到了“prepare”訊息,也不影響協議的一致性也不會阻塞其他流程,唯一的缺點是,該事務可能原本可以提交,現在卻被放棄
參與者在 READY 狀態超時
參與者在 READY 狀態等待協調者傳送的“global-commit”或“global-abort”訊息超時。出現
這種超時的原因可能是協調者宕機也可能是網路中斷。
因為參與者處於 READY 狀態,說明參與者之前一定已經發送了“vote-commit”訊息,從而參
與者已經不能改變自己的投票選擇。此時,參與者只能不斷重發“vote-commit”訊息,直到收到協
調者的“global-commit”或“global-abort”訊息後流程才可繼續。可以這麼認為,兩階段提交協議
對於這種超時的相關異常也沒有很好的容錯機制,整個流程只能阻塞在這裡,且對於參與者而言流
程狀態處於未知,參與者即不能提交本地節點上的事務,也不能放棄本地節點事務
協議分析
兩階段提交協議在工程實踐中真正使用的較少,主要原因有以下幾點:
- 兩階段提交協議的容錯能力較差。從上文的分析可以看出,兩階段提交協議在某些情況下存在流程無法執行下去的情況,且也無法判斷流程狀態。在工程中好的分散式協議往往總是可以在即使發生異常的情況下也能執行下去
- 兩階段提交協議的效能較差。一次成功的兩階段提交協議流程中,協調者與每個參與者之間至少需要兩輪互動 4 個訊息“prepare”、“vote-commit”、“global-commit”、“確認 global-commit”。過多的互動次數會降低效能。另一方面,協調者需要等待所有的參與者的投票結果,一旦存在較慢的參與者,會影響全域性流程執行速度
雖然存在一些改進的兩階段提交協議可以提高容錯能力和效能,然而這類協議依舊是在工程中使用較少的一類協議,其理論價值大於實踐意義