背景數據庫
分佈式事務是企業集成中的一個技術難點,也是每個分佈式系統架構中都會涉及到的一個東西,特別是在微服務架構中,幾乎能夠說是沒法避免。編程
ACID
指數據庫事務正確執行的四個基本要素:
原子性(Atomicity)
一致性(Consistency)
隔離性(Isolation)
持久性(Durability)網絡
CAP
CAP原則又稱CAP定理,指的是在一個分佈式系統中,一致性(Consistency)、可用性(Availability)、分區容忍性(Partition tolerance)。CAP 原則指的是,這三個要素最多隻能同時實現兩點,不可能三者兼顧。
一致性:在分佈式系統中的全部數據備份,在同一時刻是否一樣的值。
可用性:在集羣中一部分節點故障後,集羣總體是否還能響應客戶端的讀寫請求。
分區容忍性:以實際效果而言,分區至關於對通訊的時限要求。系統若是不能在時限內達成數據一致性,就意味着發生了分區的狀況,必須就當前操做在C和A之間作出選擇。架構
BASE理論
BASE理論是對CAP中的一致性和可用性進行一個權衡的結果,理論的核心思想就是:咱們沒法作到強一致,但每一個應用均可以根據自身的業務特色,採用適當的方式來使系統達到最終一致性。
Basically Available(基本可用)
Soft state(軟狀態)
Eventually consistent(最終一致性)併發
解決方案異步
01
兩階段提交(2PC)
兩階段提交2PC是分佈式事務中最強大的事務類型之一,兩段提交就是分兩個階段提交,第一階段詢問各個事務數據源是否準備好,第二階段才真正將數據提交給事務數據源。分佈式
爲了保證該事務能夠知足ACID,就要引入一個協調者(Cooradinator)。其餘的節點被稱爲參與者(Participant)。協調者負責調度參與者的行爲,並最終決定這些參與者是否要把事務進行提交。處理流程以下:微服務
階段一
a) 協調者向全部參與者發送事務內容,詢問是否能夠提交事務,並等待答覆。
b) 各參與者執行事務操做,將 undo 和 redo 信息記入事務日誌中(但不提交事務)。
c) 如參與者執行成功,給協調者反饋 yes,不然反饋 no。高併發
階段二
若是協調者收到了參與者的失敗消息或者超時,直接給每一個參與者發送回滾(rollback)消息;不然,發送提交(commit)消息。兩種狀況處理以下:性能
狀況1:當全部參與者均反饋 yes,提交事務
a) 協調者向全部參與者發出正式提交事務的請求(即 commit 請求)。
b) 參與者執行 commit 請求,並釋放整個事務期間佔用的資源。
c) 各參與者向協調者反饋 ack(應答)完成的消息。
d) 協調者收到全部參與者反饋的 ack 消息後,即完成事務提交。
狀況2:當有一個參與者反饋 no,回滾事務
a) 協調者向全部參與者發出回滾請求(即 rollback 請求)。
b) 參與者使用階段 1 中的 undo 信息執行回滾操做,並釋放整個事務期間佔用的資源。
c) 各參與者向協調者反饋 ack 完成的消息。
d) 協調者收到全部參與者反饋的 ack 消息後,即完成事務。
問題
1) 性能問題:全部參與者在事務提交階段處於同步阻塞狀態,佔用系統資源,容易致使性能瓶頸。
2) 可靠性問題:若是協調者存在單點故障問題,或出現故障,提供者將一直處於鎖定狀態。
3) 數據一致性問題:在階段 2 中,若是出現協調者和參與者都掛了的狀況,有可能致使數據不一致。
優勢:儘可能保證了數據的強一致,適合對數據強一致要求很高的關鍵領域。(其實也不能100%保證強一致)。
缺點:實現複雜,犧牲了可用性,對性能影響較大,不適合高併發高性能場景。
02
三階段提交(3PC)
三階段提交是在二階段提交上的改進版本,3PC最關鍵要解決的就是協調者和參與者同時掛掉的問題,因此3PC把2PC的準備階段再次一分爲二,這樣三階段提交。處理流程以下:
階段一
a) 協調者向全部參與者發出包含事務內容的 canCommit 請求,詢問是否能夠提交事務,並等待全部參與者答覆。
b) 參與者收到 canCommit 請求後,若是認爲能夠執行事務操做,則反饋 yes 並進入預備狀態,不然反饋 no。
階段二
協調者根據參與者響應狀況,有如下兩種可能。
狀況1:全部參與者均反饋 yes,協調者預執行事務
a) 協調者向全部參與者發出 preCommit 請求,進入準備階段。
b) 參與者收到 preCommit 請求後,執行事務操做,將 undo 和 redo 信息記入事務日誌中(但不提交事務)。
c) 各參與者向協調者反饋 ack 響應或 no 響應,並等待最終指令。
狀況2:只要有一個參與者反饋 no,或者等待超時後協調者尚沒法收到全部提供者的反饋,即中斷事務
a) 協調者向全部參與者發出 abort 請求。
b) 不管收到協調者發出的 abort 請求,或者在等待協調者請求過程當中出現超時,參與者均會中斷事務。
階段三
該階段進行真正的事務提交,也能夠分爲如下兩種狀況。
狀況 1:全部參與者均反饋 ack 響應,執行真正的事務提交
a) 若是協調者處於工做狀態,則向全部參與者發出 do Commit 請求。
b) 參與者收到 do Commit 請求後,會正式執行事務提交,並釋放整個事務期間佔用的資源。
c) 各參與者向協調者反饋 ack 完成的消息。
d) 協調者收到全部參與者反饋的 ack 消息後,即完成事務提交。
狀況2:只要有一個參與者反饋 no,或者等待超時後協調組尚沒法收到全部提供者的反饋,即回滾事務。
a) 若是協調者處於工做狀態,向全部參與者發出 rollback 請求。
b) 參與者使用階段 1 中的 undo 信息執行回滾操做,並釋放整個事務期間佔用的資源。
c) 各參與者向協調組反饋 ack 完成的消息。
d) 協調組收到全部參與者反饋的 ack 消息後,即完成事務回滾。
優勢:相比二階段提交,三階段提交下降了阻塞範圍,在等待超時後協調者或參與者會中斷事務。避免了協調者單點問題。階段 3 中協調者出現問題時,參與者會繼續提交事務。
缺點:數據不一致問題依然存在,當在參與者收到 preCommit 請求後等待 do commite 指令時,此時若是協調者請求中斷事務,而協調者沒法與參與者正常通訊,會致使參與者繼續提交事務,形成數據不一致。
03
補償事務(TCC)
TCC 是服務化的二階段編程模型,採用的補償機制:
條件:
須要實現確認和補償邏輯
須要支持冪等
處理流程:
a) Try 階段主要是對業務系統作檢測及資源預留。
這個階段主要完成:
完成全部業務檢查( 一致性 ) 。
預留必須業務資源( 準隔離性 ) 。
Try 嘗試執行業務。
b) Confirm 階段主要是對業務系統作確認提交。
Try階段執行成功並開始執行 Confirm階段時,默認 Confirm階段是不會出錯的。即:只要Try成功,Confirm必定成功。
c) Cancel 階段主要是在業務執行錯誤,須要回滾的狀態下執行的業務取消,預留資源釋放。
優勢:
性能提高:具體業務來實現控制資源鎖的粒度變小,不會鎖定整個資源。
數據最終一致性:基於 Confirm 和 Cancel 的冪等性,保證事務最終完成確認或者取消,保證數據的一致性。
可靠性:解決了 XA 協議的協調者單點故障問題,由主業務方發起並控制整個業務活動,業務活動管理器也變成多點,引入集羣。
缺點:TCC 的 Try、Confirm 和 Cancel 操做功能要按具體業務來實現,業務耦合度較高,提升了開發成本。
04
本地消息表(消息隊列)
其核心思想是將分佈式事務拆分紅本地事務進行處理。
方案經過在消費者額外新建事務消息表,消費者處理業務和記錄事務消息在本地事務中完成,輪詢事務消息表的數據發送事務消息,提供者基於消息中間件消費事務消息表中的事務。
條件:
服務消費者須要建立一張消息表,用來記錄消息狀態。
服務消費者和提供者須要支持冪等。
須要補償邏輯。
每一個節點上起定時線程,檢查未處理完成或發出失敗的消息,從新發出消息,即重試機制和冪等性機制。
處理流程:
容錯處理狀況以下:
當步驟1處理出錯,事務回滾,至關於什麼都沒有發生。
當步驟二、3處理出錯,因爲消息保存在消費者表中,能夠從新發送到MQ進行重試。
若是步驟3處理出錯,且是業務上的失敗,服務提供者發送消息通知消費者事務失敗,且此時變爲消費者發起回滾事務進行回滾邏輯。
優勢:從應用設計開發的角度實現了消息數據的可靠性,消息數據的可靠性不依賴於消息中間件,弱化了對 MQ 中間件特性的依賴。
缺點:與具體的業務場景綁定,耦合性強,不可公用。消息數據與業務數據同庫,佔用業務系統資源。業務系統在使用關係型數據庫的狀況下,消息服務性能會受到關係型數據庫併發性能的侷限。
MQ事務消息(最終一致性)
支持事務消息的MQ,其支持事務消息的方式採用相似於二階段提交。
基於 MQ 的分佈式事務方案實際上是對本地消息表的封裝,將本地消息表基於 MQ 內部,其餘方面的協議基本與本地消息表一致。
條件:
a) 須要補償邏輯
b) 業務處理邏輯須要冪等
處理流程:
c) 消費者向MQ發送half消息。
d) MQ Server將消息持久化後,向發送方ack確認消息發送成功。
e) 消費者開始執行事務邏輯。
f) 消費者根據本地事務執行結果向MQ Server提交二次確認或者回滾。
g) MQ Server收到commit狀態則將half消息標記可投遞狀態。
h) 服務提供者收到該消息,執行本地業務邏輯。返回處理結果。
優勢:
消息數據獨立存儲,下降業務系統與消息系統之間的耦合。
吞吐量優於本地消息表方案。
缺點:
一次消息發送須要兩次網絡請求(half消息 + commit/rollback)。
須要實現消息回查接口。
05
Sagas事務模型(最終一致性)
Saga模式是一種分佈式異步事務,一種最終一致性事務,是一種柔性事務,有兩種不一樣的方式來實現saga事務,最流行的兩種方式是:
1、 事件/編排Choreography:沒有中央協調器(沒有單點風險)時,每一個服務產生並聆聽其餘服務的事件,並決定是否應採起行動。
該實現第一個服務執行一個事務,而後發佈一個事件。該事件被一個或多個服務進行監聽,這些服務再執行本地事務併發布(或不發佈)新的事件,當最後一個服務執行本地事務而且不發佈任何事件時,意味着分佈式事務結束,或者它發佈的事件沒有被任何Saga參與者聽到都意味着事務結束。
處理流程:
訂單服務保存新訂單,將狀態設置爲pengding掛起狀態,併發布名爲ORDER_CREATED_EVENT的事件。
支付服務監聽ORDER_CREATED_EVENT,並公佈事件BILLED_ORDER_EVENT。
庫存服務監聽BILLED_ORDER_EVENT,更新庫存,併發布ORDER_PREPARED_EVENT。
貨運服務監聽ORDER_PREPARED_EVENT,而後交付產品。最後,它發佈ORDER_DELIVERED_EVENT。
最後,訂單服務偵聽ORDER_DELIVERED_EVENT並設置訂單的狀態爲concluded完成。
假設庫存服務在事務過程當中失敗了。進行回滾:
庫存服務產生PRODUCT_OUT_OF_STOCK_EVENT
訂購服務和支付服務會監聽到上面庫存服務的這一事件:
①支付服務會退款給客戶。
②訂單服務將訂單狀態設置爲失敗。
優勢:事件/編排是實現Saga模式的天然方式; 它很簡單,容易理解,不須要太多的努力來構建,全部參與者都是鬆散耦合的,由於他們彼此之間沒有直接的耦合。若是您的事務涉及2至4個步驟,則多是很是合適的。
2、 命令/協調orchestrator:中央協調器負責集中處理事件的決策和業務邏輯排序。
saga協調器orchestrator以命令/回覆的方式與每項服務進行通訊,告訴他們應該執行哪些操做。
訂單服務保存pending狀態,並要求訂單Saga協調器(簡稱OSO)開始啓動訂單事務。
OSO向收款服務發送執行收款命令,收款服務回覆Payment Executed消息。
OSO向庫存服務發送準備訂單命令,庫存服務將回復OrderPrepared消息。
OSO向貨運服務發送訂單發貨命令,貨運服務將回復Order Delivered消息。
OSO訂單Saga協調器必須事先知道執行「建立訂單」事務所需的流程(經過讀取BPM業務流程XML配置得到)。若是有任何失敗,它還負責經過向每一個參與者發送命令來撤銷以前的操做來協調分佈式的回滾。當你有一箇中央協調器協調一切時,回滾要容易得多,由於協調器默認是執行正向流程,回滾時只要執行反向流程便可。
優勢:
避免服務之間的循環依賴關係,由於saga協調器會調用saga參與者,但參與者不會調用協調器。
集中分佈式事務的編排。
只須要執行命令/回覆(其實回覆消息也是一種事件消息),下降參與者的複雜性。
在添加新步驟時,事務複雜性保持線性,回滾更容易管理。
若是在第一筆交易尚未執行完,想改變有第二筆事務的目標對象,則能夠輕鬆地將其暫停在協調器上,直到第一筆交易結束。
缺點:協調器中集中太多邏輯的風險。