分散式事務常常使用2階段提交或者3階段提交,那麼這兩種方式的區別是什麼?3階段提交協議是不是就完美了?圖文解釋,簡單易懂。 ...
一,分散式事務簡介
在當前互聯網,大數據和人工智慧的熱潮中,傳統企業也受到這一潮流的衝擊,紛紛響應國家“互聯網+”的戰略號召,企業開始將越來越多的應用從公司內網遷移到雲端和移動端,或者將之前孤立的IT系統聯網整合,或者將原來厚重的企業應用拆分重組,獨立成一個個輕量級的應用對外提供服務,這對傳統的業務處理的數據一致性,帶來了嚴重的挑戰,我們已經身處一個分散式的計算環境,分散式事務的需求越來越普遍。
舉一個例子,某行業電商網站經過幾年的發展,業務數據累積越來越多,查詢越來越慢。經過內部評審分析,認為系統的瓶頸就是資料庫壓力過大,如果要解決這問題,必須分表分庫,比如將訂單,商品,用戶分佈到不同的資料庫去,但這樣隨之帶來一個問題,原來處理業務的時候使用的是本地事務,分庫後就需要使用分散式事務了。
那麼應該如何實現分散式事務呢?
這裡我們需要明確一點,並非資料庫天然就是分散式的在執行操作的,事務都是在一個資料庫實例上進行的,如果要執行一個分散式事務的操作,那麼就需要協調多個分散的資料庫上執行的事務操作。所以在分散式事務中,有2個概念:
l Distributed Transaction Resource Owner (簡稱DTR):
n --分散式事務資源伺服器,擁有事務資源的伺服器,如絕大部分關係資料庫,一些消息隊列,或者一些能夠執行類似事務操作的應用。
l Distributed Transaction Coordinate Controller (簡稱DTC):
n --分散式事務協調控制器,它協調控制分散式事務環境中的事務資源伺服器,發送指令給它們並且處理事務資源伺服器返回的結果。
二,分散式事務的實現層面
在分散式事務的具體實現層面,可以在資料庫層直接實現,也可以在應用服務層面實現。如果是在應用服務層面實現,本質上它也可能是調用本地的資料庫事務。
下麵是DTR與DTC的拓撲關係圖:
基於關係資料庫層面介面實現的分散式事務
基於資料庫的分散式事務,一般在應用程式的數據層調用系統的分散式事務組件,應用程式執行本地事務的時候,先選舉出一個分散式事務協調器,然後協調器來協調各個本地事務的執行。由於是在應用程式的數據層進行的調用,所以它對遠程資料庫的操作是在本地進程內的。如果你的應用部署在多台伺服器上,那麼在每一臺操作資料庫的應用伺服器上都要安裝運行分散式事務協調器服務。
基於應用服務層面實現的分散式事務
基於應用服務層面的分散式事務,是在應用服務層面進行的事務控制,它同樣會有分散式事務協調控制器,和事務資源伺服器。與基於資料庫層面的分散式事務不同,事務的類型支持更廣泛,比如消息隊列訪問,文件寫入或者具有補償操作的業務應用程式,都可以成為事務資源,並且不要求這些事務資源本身支持分散式事務。舉個例子,事務資源A是Windows上的SQLSERVER資料庫,事務B是Linux上的MySQL資料庫,這時候事務B就沒法使用Windows上的事務協調控制器MSDTC了。而基於服務層面的分散式事務,可以解決這個問題。
三,分散式事務的2階段提交協議(2PC)
第一階段(1PC):提交投票階段
協調器向事務資源伺服器發出 CanCommit 的是否可以提交事務的詢問指令,事務資源伺服器收到此指令後,準備好要提交的事務資源,再向協調器回覆 YES;如果沒有準備好,比如執行事務中的操作出現了錯誤,應該回覆 NO.如果某DTR無法回覆,DTC也認為該DTR的結果是NO.
第一階段,全部回覆為YES,代表各個事務資源伺服器均已經準備好了提交。
第一階段,事務資源伺服器DTR-2回覆為NO,如果DTC等待DTR-2超過設定時間都沒有得到回覆,或者DTR-2與DTC斷開了連接,也認為DTR-2的結果是NO
第二階段(2 PC):提交或終止階段
協調器統計所有事物資源伺服器的回覆數量,如果全部回覆為YES,則向所有事物資源伺服器發出Commit指令,否則,發出Abort指令。資源伺服器收到指令後,執行相應的操作。
二階段提交事務的數據不一致問題
在第二階段(2PC),如果DTR沒有收到DTC的指令改怎麼辦呢?
如果等到超時都沒有收到DTC的指令,DTR處於“可以提交”或者“不可以提交”的雙重狀態,也就是提交狀態不可知。假設DTR1沒有收到DTC的提交指令或者撤銷指令,DTR1可以假設DTR2也不會收到指令,因為此時大概率是DTC宕機或者網路整體不良,那麼DTR1最佳的做法是回滾事務。
但是,如果僅僅是DTR1受網路影響沒有收到提交指令,而DTR2收到了提交指令,那麼DTR1回滾事務,DTR2提交了事務,整個分散式事務就是失敗的,數據發生了不一致。
因此,2階段提交的分散式事務不是高可靠的分散式事務控制模型,需要在事務資源的提交環節做更多的驗證,這便是3階段提交的分散式事務。
不過,對於大部分系統,2階段提交的分散式事務已經能夠滿足應用了,因為通常情況下,都是基於資料庫應用層實現的分散式事務,並且各個事務資源節點都在同一個區域網內,發生網路不穩定的概率非常小,並且現在不少資料庫都會做高可靠性的資料庫集群,發生宕機的可能性也非常小,最終出現數據不一致的概率也就非常小了。
如果系統的應用環境不能滿足上面說的任何一個條件,即分散式事務的控制不是在資料庫應用層,子系統不在一個區域網,或者資料庫沒有做高可靠的集群,並且對於系統的事務一致性要求非常高,那麼應該使用3階段提交協議來實現分散式事務。
四,分散式事務的3階段提交協議(3PC)
對2階段提交協議的分析我們發現,2PC的事務提交階段狀態是不確定的,整個事務容易出現不一致的情況。所以,我們隊2PC的提交階段,進一步拆分成“預提交”階段和提交階段,增加事務提交狀態的確認過程。
第一階段(1PC):提交投票階段
協調器向事務資源伺服器發出 CanCommit 的是否可以提交事務的詢問指令,事務資源伺服器收到此指令後,準備好要提交的事務資源,再向協調器回覆 YES;如果沒有準備好,比如執行事務中的操作出現了錯誤,應該回覆 NO.如果某DTR無法回覆,DTC也認為該DTR的結果是NO.
該階段的處理過程跟2階段提交協議的第一階段是一樣的,處理流程圖參考前面,此略。
第二階段(2 PC):預提交或終止階段
預提交事務
協調器(DTC)統計所有事務資源伺服器(DTR)的回覆數量,如果全部回覆為YES,則向所有事物資源伺服器發出PreCommit指令,否則,發出Abort指令。資源伺服器收到指令後,執行相應的操作。
在第二階段,如果DTR收到PreCommit指令,則向DTC回覆ACK消息,表示收到了指令,準備提交,接著,進入第三階段,等待最終的提交指令。
終止事務
在第二階段,如果在第一階段有節點異常,DTC發出撤銷指令,DTR收到了撤銷指令,那麼它執行回滾本地事務的操作。如果由於網路原因,某個DTR一直等到超時都沒有收到PreCommit指令,那麼它執行Abort撤銷指令,回滾本地事務。
第三階段(3 PC):提交或終止階段
提交分散式事務
協調器(DTC)統計所有事務資源伺服器(DTR)在第二階段的回覆數量,如果全部回覆為ACK,則向所有DTR發出Commit指令。DTR收到指令後,執行事務提交操作,並返回Commit Done消息,DTC收到此消息,結束整個分散式事務過程。
回滾分散式事務
協調器(DTC)統計所有事務資源伺服器(DTR)在第二階段的回覆數量,如果未收到全部回覆為ACK,則它認為有節點可能出現了網路故障,此節點沒有收到PreCommit指令或者雖然收到了卻沒有回覆ACK,測試DTC應該向所有DTR節點發出撤銷指令。各DTR收到撤銷指令後,回滾本地事務,然後回覆消息,DTC完成本次事務過程。
三階段提交事務也並不完美
考察第3階段的提交分散式事務的情況,DTR1收到了Commit指令,但是由於網路原因,DTR2沒有收到此指令,那麼DTR2是提交本地事務還是回滾本地事務?
站在DTR2的角度,它在本階段可能收到Commit指令,也可能收到Abort指令,那麼它既可以提交本地事務也可以回滾本地事務,兩種操作是不確定的,所以,3階段提交協議,仍然不是完美的,不能百分之百保證數據的最終一致性。
既然3階段提交協議仍然有不確定性,那麼相比2階段提交協議有什麼意義呢?
仔細想下,DTR2已經進入第3階段了,那麼肯定其它DTR都進入了第3階段,而進入第3階段的前提是各DTR節點都收到過PreCommit指令,都是已經準備好提交只等最後的提交指令了,否則各節點在第二階段應該收到撤銷指令,不會再進入第三階段。既然各DTR節點都進入了第三階段,它們都準備好提交事務了,那麼即使沒有收到最終的Commit指令,DTC發出Commit指令也是大概率的。所以,從概率上講,如果在第三階段,DTR沒有收到Abort撤銷指令,也沒收到Commit提交指令,那麼它預設應該指向Commit指令,提交本地事務。相比第二階段某DTR節點沒有收到指令而認為應該收到PreCommit指令的概率,要大得多。
關於第三階段沒有收到指令而應該大概率執行Commit指令的問題,理解起來可能有點困難,我給同事講的時候大部分同事也難以理解,可能是我表述的問題,大家有更好的解釋方式,歡迎交流,不勝感激!
5,實現 3階段提交的分散式事務
本文將介紹一個基於服務層面而不是資料庫層面的,3階段提交的分散式事務中間件的設計開發過程。這個中間件必須解決下麵幾個問題:
l 通信組件—分散式事務控制器(DTC),分散式事務資源伺服器(DTR)都是獨立的服務,這些服務部署在不同的通信節點,它們之間需要進行可靠的網路通信,因此通信組件是基礎;
l 數據訪問組件—提供基礎的數據讀寫操作,並且能夠操作本地事務。
l 服務組件—將DTC,DTR的功能代碼編寫為相應的SOA服務組件
l 關係資料庫—具有事務功能的關係資料庫,可以是嵌入式的本地資料庫,比如SQLite,也可以是伺服器客戶機模式的網路資料庫,比如SQLSERVER。
各組件的關係圖如下:
PDF.NET的消息服務框架(MSF)具有開發服務組件基礎的介面和一套消息通信組件,同時還有一個服務容器,可以承載本篇文章說的分散式事務控制器DTC,分散式事務資源服務DTR這些服務應用,同時PDF.NET還有一個強大的數據訪問組件 PDF.NET SOD,下一篇文章,我們將來具體討論基於MSF和SOD的3階段分散式事務應用的實現過程,它的源碼已經發佈在 https://github.com/bluedoctor/MSF-DistTransExample ,大家可以先睹為快。