之前我已經講過了二階段(2PC)的概念了,這就不重複講解了。在分散式系統裡面如果在某一個系統在執行過程中失敗了,或者由於網路原因沒有收到請求,那麼,整個系統可能就有不一致的現象了,即:付了錢,扣了紅包,但是庫存沒有扣減,這就是所謂的分散式系統的資料一致性問題。
在二階段提交(2PC)存在諸多問題的情況下,人們提出了三階段提交(3PC),主要用來解決2PC存在的一些問題。
所謂3PC,就是把2PC的準備階段再次一分為二,組成了三階段。
-
在第一階段,只是詢問所有參與者是否可以執行事務操作,並不在本階段執行事務操作。當協調者收到所有的參與者都返回YES時
-
在第二階段才執行事務操作,然後在第三階段在執行commit或者rollback。
-
這樣三階段提交就有CanCommit(事務詢問)、PreCommit(事務執行)、DoCommit(事務提交)三個階段。
PS:3PC並沒徹底解決2PC存在的所有問題
和二階段提交對比,三階段提交主要是在2PC的第一階段和第二階段中插入一個準備階段。保證了在最後提交階段之前各參與節點的狀態是一致的。
接下來看看具體執行過程。
- CanCommit
3PC的CanCommit階段其實和2PC的準備階段很像。協調者向參與者傳送commit請求,參與者如果可以提交就返回Yes響應,否則返回No響應。
-
事務詢問:協調者向參與者傳送CanCommit請求。詢問是否可以執行事務提交操作。然後開始等待參與者的響應。
-
響應反饋:參與者接到CanCommit請求之後,正常情況下,如果其自身認為可以順利執行事務,則返回YES響應,並進入預備狀態。否則反饋NO
-
PreCommit階段
協調者根據CanCommit
階段參與者的反應情況來決定是否可以進行事務的PreCommit
操作。
假如協調者從所有的參與者獲得的反饋都是YES響應,那麼就會執行事務的預執行:
-
傳送預提交請求:協調者向參與者傳送PreCommit請求,並進入Prepared階段。
-
事務預提交:參與者接收到PreCommit請求後,會執行事務操作,並將undo和redo資訊記錄到事務日誌中。
-
響應反饋:如果參與者成功的執行了事務操作,則返回ACK響應,同時開始等待最終指令。
假如有任何一個參與者向協調者傳送了NO響應,或者等待超時之後,協調者都沒有接到參與者的響應,那麼就執行事務的中斷。
-
傳送中斷請求:協調者向所有參與者傳送abort請求。
-
中斷事務:參與者收到來自協調者的abort請求之後(或超時之後,仍未收到協調者的請求),執行事務的中斷。
-
doCommit階段
該階段進行真正的事務提交,也可以分為以下兩種情況。
如果協調證收到所有參與者的事務執行後的ACK響應,則發生如下事情
-
傳送提交請求:協調接收到參與者傳送的ACK響應,那麼他將從預提交狀態進入到提交狀態。並向所有參與者傳送doCommit請求。
-
事務提交:參與者接收到doCommit請求之後,執行正式的事務提交。並在完成事務提交之後釋放所有事務資源。
-
響應反饋:事務提交完之後,向協調者傳送Ack響應。
-
完成事務:協調者接收到所有參與者的ack響應之後,完成事務。
如果協調者沒有接收到參與者傳送的ACK響應(可能是接受者傳送的不是ACK響應,也可能響應超時),那麼就會執行中斷事務。
-
傳送中斷請求:協調者向所有參與者傳送abort請求
-
事務回滾:參與者接收到abort請求之後,利用其在階段二記錄的undo資訊來執行事務的回滾操作,並在完成回滾之後釋放所有的事務資源。
-
反饋結果:參與者完成事務回滾之後,向協調者傳送ACK訊息
-
中斷事務:協調者接收到參與者反饋的ACK訊息之後,執行事務的中斷。
還有一種情況,如果參與者無法及時接收到來自協調者的doCommit或者abort請求時,會在等待超時之後,會繼續進行事務的提交。
以上,就是3PC的三個主要階段的操作流程。
- 降低同步阻塞。
在3PC中,第一階段並沒有讓參與者直接執行事務,而是在第二階段才會讓參與者進行事務的執行。大大降低了阻塞的概率和時長。並且,在3PC中,如果參與者未收到協調者的訊息,那麼他會在等待一段時間後自動執行事務的commit,而不是一直阻塞。
- 提升了資料一致性
2PC中有一種情況會導致資料不一致,如在2PC的階段二中,當協調者向參與者傳送commit請求之後,發生了網路異常,只有一部分參與者接受到了commit請求。而在這部分參與者接到commit請求之後就會執行commit操作。但是其他部分未接到commit請求的機器則無法執行事務提交。於是整個分散式系統便出現了資料不一致性的現象。
這種情況在3PC的場景中得到了很好的解決,因為在3PC中,如果參與者沒有收到協調者的訊息時,他不會一直阻塞,過一段時間之後,他會自動執行事務。這就解決了那種協調者發出commit之後。
另外,2PC還有個問題無法解決。那就是協調者再發出commit訊息之後當機,而唯一接收到這條訊息的參與者同時也當機了。那麼即使協調者通過選舉協議產生了新的協調者,這條事務的狀態也是不確定的,沒人知道事務是否被已經提交。
這種情況在3PC中是有辦法解決的,因為在3PC中,選出新的協調者之後,他可以諮詢所有參與者的狀態,如果有某一個處於commit狀態或者prepare-commit狀態,那麼他就可以通知所有參與者執行commit,否則就通知大家rollback。因為3PC的第三階段一旦有機器執行了commit,那必然第一階段大家都是同意commit的,所以可以放心執行commit。
在doCommit階段,如果參與者無法及時接收到來自協調者的doCommit或者abort請求時,會在等待超時之後,會繼續進行事務的提交。
所以,由於網路原因,協調者傳送的abort響應沒有及時被參與者接收到,那麼參與者在等待超時之後執行了commit操作。這樣就和其他接到abort命令並執行回滾的參與者之間存在資料不一致的情況。
所以,我們可以認為,無論是二階段提交還是三階段提交都無法徹底解決分散式的一致性問題。
- 摘自 漫話程式設計