在一系列微服務系統當中,假如不存在分佈式事務,會發生什麼呢?以互聯網中經常使用的交易業務爲例子:數據庫
上圖中包含了庫存和訂單兩個獨立的微服務,每一個微服務維護了本身的數據庫。在交易系統的業務邏輯中,一個商品在下單以前須要先調用庫存服務,進行扣除庫存,再調用訂單服務,建立訂單記錄。網絡
正常狀況下,兩個數據庫各自更新成功,兩邊數據維持着一致性。異步
可是,在非正常狀況下,有可能庫存的扣減完成了,隨後的訂單記錄卻由於某些緣由插入失敗。這個時候,兩邊數據就失去了應有的一致性。分佈式
這種時候必需要保證數據的一致性。單數據源的一致性依靠單機事務來保證,多數據源的一致性就要依靠分佈式事務。微服務
那麼,什麼是分佈式事務呢?性能
分佈式事務用於在分佈式系統中保證不一樣節點之間的數據一致性。分佈式事務的實現有不少種,最具備表明性的是由Oracle Tuxedo系統提出的XA分佈式事務協議。spa
XA協議包含兩階段提交(2PC)和三階段提交(3PC)兩種實現,這裏重點介紹兩階段提交的具體過程。3d
若是玩過魔獸世界的朋友應該知道,XA協議的運做方式和魔獸世界中的團隊協做有些類似。在魔獸世界這款遊戲中,副本組團打BOSS的時候,爲了更方便隊長與隊員們之間的協做,隊長能夠發起一個「就位確認」的操做:中間件
當隊員收到就位確認提示後,若是已經就位,就選擇「是」,若是還沒就位,就選擇「否」。blog
當隊長收到了全部人的就位確認,就會向全部隊員們發佈消息,告訴他們開始打BOSS。
相應的,在隊長髮起就位確認的時候,有可能某些隊員尚未就位:
以上就是魔獸世界當中組團打BOSS的確認流程。這個流程和XA分佈式事務協議的兩階段提交很是類似。
那麼XA協議到底是什麼樣子呢?在XA協議中包含着兩個角色:事務協調者和事務參與者。來看一看他們之間的交互流程:
第一階段:
在XA分佈式事務的第一階段,做爲事務協調者的節點會首先向全部的參與者節點發送Prepare請求。
在接到Prepare請求以後,每個參與者節點會各自執行與事務有關的數據更新,寫入Undo Log和Redo Log。若是參與者執行成功,暫時不提交事務,而是向事務協調節點返回「完成」消息。
當事務協調者接到了全部參與者的返回消息,整個分佈式事務將會進入第二階段。
第二階段:
在XA分佈式事務的第二階段,若是事務協調節點在以前所收到都是正向返回,那麼它將會向全部事務參與者發出Commit請求。
接到Commit請求以後,事務參與者節點會各自進行本地的事務提交,並釋放鎖資源。當本地事務完成提交後,將會向事務協調者返回「完成」消息。
當事務協調者接收到全部事務參與者的「完成」反饋,整個分佈式事務完成。
以上所描述的是XA兩階段提交的正向流程,接下來看一看失敗狀況的處理流程:
第一階段:
第二階段:
在XA的第一階段,若是某個事務參與者反饋失敗消息,說明該節點的本地事務執行不成功,必須回滾。
因而在第二階段,事務協調節點向全部的事務參與者發送Abort請求。接收到Abort請求以後,各個事務參與者節點須要在本地進行事務的回滾操做,回滾操做依照Undo Log來進行。
以上就是XA兩階段提交協議的詳細過程。
XA兩階段提交雖然解決了分佈式事務的一致性問題,可是仍然存在着不少不足之處。
XA兩階段提交究竟有哪些不足呢?
1.性能問題
XA協議遵循強一致性。在事務執行過程當中,各個節點佔用着數據庫資源,只有當全部節點準備完畢,事務協調者纔會通知提交,參與者提交後釋放資源。這樣的過程有着很是明顯的性能問題。
2.協調者單點故障問題
事務協調者是整個XA模型的核心,一旦事務協調者節點掛掉,參與者收不到提交或是回滾通知,參與者會一直處於中間狀態沒法完成事務。
3.丟失消息致使的不一致問題。
在XA協議的第二個階段,若是發生局部網絡問題,一部分事務參與者收到了提交消息,另外一部分事務參與者沒收到提交消息,那麼就致使了節點之間數據的不一致。
如何避免XA兩階段提交的種種問題呢?有許多其餘的分佈式事務方案可供選擇:
1.XA三階段提交
XA三階段提交在兩階段提交的基礎上增長了CanCommit階段,而且引入了超時機制。一旦事物參與者遲遲沒有接到協調者的commit請求,會自動進行本地commit。這樣有效解決了協調者單點故障的問題。可是性能問題和不一致的問題仍然沒有根本解決。
2.MQ事務
利用消息中間件來異步完成事務的後一半更新,實現系統的最終一致性。這個方式避免了像XA協議那樣的性能問題。
3.TCC事務
TCC事務是Try、Commit、Cancel三種指令的縮寫,其邏輯模式相似於XA兩階段提交,可是實現方式是在代碼層面來人爲實現。