今天,我們來聊聊分散式事務
前言
我們都知道資料庫的事務滿足"ACID"特性,A是指事務的原子性,C是指事務的一致性,I指事務的隔離性,D指永續性。
最開始我們的資料量都很小,所有的資料都落在一個數據庫中。MySQL資料庫單表的最大資料量在百萬條左右,隨著系統變大,資料越來越多,這個時候我們不得不將資料分佈在不同的資料庫中存放,也就是常說的資料分片(sharding)。我們可以通過一定的分庫策略將同一個交易鏈路上的資料放到一個數據庫中,例如我們可以將一個訂單所有產生的資料放到一個數據庫中,按照訂單號來分庫,這樣我們在生成訂單相關資料的時候可以在單個數據庫上開啟事務來完成。
這樣看似完美的解決方案其實並不完美。例如我們想記錄使用者維度的訂單資料時,這個方案就無能為力了。於是分散式事務應運而生。
分散式系統CAP BASE理論
說到分散式系統,不得不說CAP和BASE理論,它是指導我們分散式系統的理論基礎。
CAP理論
加州大學伯克利分校Eric Brewer教授支援一個分散式系統無法滿足這樣三條特性:
Consistency,一致性:多個操作同時生效,不會出現部分生效的情況
Availability,可用性:客戶端的每個請求在服務端能夠正確被響應
Partition tolerance,分割槽容錯性:分割槽中部分節點掛了不會影響整體服務可用性,這也是分散式系統最基本的要求
分割槽容錯性是一個分散式系統最基本的要求,因此一般分散式系統都會滿足分割槽容錯性,否則就失去了分散式系統的意義。分散式系統一般會在一致性和可用性上做出取捨。例如犧牲一致性換區可用性,這裡說的犧牲一致性是指犧牲掉系統的"強一致性",最終我們的系統還是一致的,即所謂的"弱一致性"或者"最終一致性"。當我們的系統需要保證強一致性時我們不得不犧牲掉可用性:當系統部分節點延遲或者down機整個系統的服務將變得不可用,也因此係統資料是強一致性的。
BASE理論
BASE理論是對CAP理論的進一步擴充:
Basically Available(基本可用)
Soft state(軟狀態)
Eventually consistent(最終一致性)
基本可用是指我們的系統無法做到百分百可用,但是可以保證例如"3個9"(99.9%)可用。軟狀態是指允許我們的系統存在中間狀態,在最終我們的系統可以達到最終一致性。BASE理論強調的是系統的最終一致性。
分散式事務
目前分散式事務的解決方案主要有:二階段提交(2PC)、柔性補償事務(TCC)、本地訊息表(非同步確保)、MQ事務訊息等。
二階段提交
二階段事務分為兩個階段:階段一事務協調者通知各個節點執行事務預提交;階段二協調者根據各個節點的響應來通知各個節點提交或者回滾事務操作。
兩階段提交這種解決方案屬於犧牲了一部分可用性來換取的一致性。
優點: 儘量保證了資料的強一致,適合對資料強一致要求很高的關鍵領域。(其實也不能100%保證強一致)
缺點: 實現複雜,犧牲了可用性,同步阻塞對效能影響較大,不適合高併發高效能場景。

補償事務(TCC)
TCC 其實就是採用的補償機制,其核心思想是:針對每個操作,都要註冊一個與其對應的確認和補償(撤銷)操作。它分為三個階段:
Try 階段主要是對業務系統做檢測及資源預留
Confirm 階段主要是對業務系統做確認提交,Try階段執行成功並開始執行 Confirm階段時,預設 Confirm階段是不會出錯的。即:只要Try成功,Confirm一定成功。
Cancel 階段主要是在業務執行錯誤,需要回滾的狀態下執行的業務取消,預留資源釋放。
舉個例子,假入 Bob 要向 Smith 轉賬,思路大概是:
我們有一個本地方法,裡面依次呼叫
首先在 Try 階段,要先呼叫遠端介面把 Smith 和 Bob 的錢給凍結起來。
在 Confirm 階段,執行遠端呼叫的轉賬的操作,轉賬成功進行解凍。
如果第2步執行成功,那麼轉賬成功,如果第二步執行失敗,則呼叫遠端凍結介面對應的解凍方法 (Cancel)。
優點: 跟2PC比起來,實現以及流程相對簡單了一些,但資料的一致性比2PC也要差一些
缺點: 缺點還是比較明顯的,在2,3步中都有可能失敗。TCC屬於應用層的一種補償方式,所以需要程式設計師在實現的時候多寫很多補償的程式碼,在一些場景中,一些業務流程可能用TCC不太好定義及處理。

本地訊息表(非同步確保)
本地訊息表這種實現方式應該是業界使用最多的,其核心思想是將分散式事務拆分成本地事務進行處理,這種思路是來源於ebay。我們可以從下面的流程圖中看出其中的一些細節:

基本思路就是:
訊息生產方,需要額外建一個訊息表,並記錄訊息傳送狀態。訊息表和業務資料要在一個事務裡提交,也就是說他們要在一個數據庫裡面。然後訊息會經過MQ傳送到訊息的消費方。如果訊息傳送失敗,會進行重試傳送。
訊息消費方,需要處理這個訊息,並完成自己的業務邏輯。此時如果本地事務處理成功,表明已經處理成功了,如果處理失敗,那麼就會重試執行。如果是業務上面的失敗,可以給生產方傳送一個業務補償訊息,通知生產方進行回滾等操作。
生產方和消費方定時掃描本地訊息表,把還沒處理完成的訊息或者失敗的訊息再發送一遍。如果有靠譜的自動對賬補賬邏輯,這種方案還是非常實用的。
這種方案遵循BASE理論,採用的是最終一致性,筆者認為是這幾種方案裡面比較適合實際業務場景的,即不會出現像2PC那樣複雜的實現(當呼叫鏈很長的時候,2PC的可用性是非常低的),也不會像TCC那樣可能出現確認或者回滾不了的情況。
優點: 一種非常經典的實現,避免了分散式事務,實現了最終一致性。
缺點: 訊息表會耦合到業務系統中,如果沒有封裝好的解決方案,會有很多雜活需要處理。
MQ事務訊息
有一些第三方的MQ是支援事務訊息的,比如RocketMQ,他們支援事務訊息的方式也是類似於採用的二階段提交,但是市面上一些主流的MQ都是不支援事務訊息的,比如 RabbitMQ 和 Kafka 都不支援。
以阿里的 RocketMQ 中介軟體為例,其思路大致為:
第一階段Prepared訊息,會拿到訊息的地址。
第二階段執行本地事務,第三階段通過第一階段拿到的地址去訪問訊息,並修改狀態。
也就是說在業務方法內要想訊息佇列提交兩次請求,一次傳送訊息和一次確認訊息。如果確認訊息傳送失敗了RocketMQ會定期掃描訊息叢集中的事務訊息,這時候發現了Prepared訊息,它會向訊息傳送者確認,所以生產方需要實現一個check介面,RocketMQ會根據傳送端設定的策略來決定是回滾還是繼續傳送確認訊息。這樣就保證了訊息傳送與本地事務同時成功或同時失敗。
優點: 實現了最終一致性,不需要依賴本地資料庫事務。
缺點: 實現難度大,主流MQ不支援。

MQ事務訊息
總結
目前分散式事務主要有:二階段提交、TCC柔性事務、本地訊息表(非同步確保)和MQ事務訊息等解決方案。二階段提交可以確保資料的強一致性,其他的解決方案屬於最終一致性解決方案。
分散式事務雖然能保證資料的強一致性,但是效能低。使用前需要確定是否真的需要分散式事務。
現在加群即可獲取Java工程化、高效能及分散式、高效能、高架構、zookeeper、效能調優、Spring、MyBatis、Netty原始碼分析和大資料等多個知識點高階進階乾貨的直播免費學習許可權及相關視訊資料,群號:923116658
點選連結加入群聊【Java架構解析】:https://jq.qq.com/?_wv=1027&k=5e1QsXb