微服務架構流行的今天,一次交易須要跨越多個「服務」、多個數據庫來實現,傳統的技術手段,已經沒法應對和知足微服務狀況下這些複雜的場景了。針對微服務下的交易業務如何保障數據一致性,本文儘可能作到理論結合實際,將咱們在實際產品中用到的分佈式事務實現機制,和你們扒一扒,但願能幫助到讀者。
談到分佈式事務,必須先把」CAP"拿出來講說事......,固然還有」BASE"......
從架構的角度來看,業務拆分(數據分區)、數據一致性、性能(可用性)永遠是個平衡的藝術:
1)在微服務架構下,爲了得到更高的性能與靈活性,將業務應用拆分爲多個,交易跨多個微服務編排,數據一致性的問題產生;
2)爲了解決數據一致性問題,須要採用不一樣的事務機制來保障,這又會產生性能(可用性)問題;
在計算機世界裏,爲了解決一件事情,另外的問題就會接踵而至,從另外一個層面印證了IT架構永遠是一種平衡的藝術。
「BASE」其核心思想是根據業務特色,採用適當的方式來使系統達到最終一致性(Eventualconsistency);在互聯網領域,一般須要犧牲強一致性來換取系統的高可用性,只須要保證數據的「最終一致」,只是這個最終時間須要在用戶能夠接受的範圍內;但在金融相關的交易領域,仍然須要採用強一致性的方式來保障交易的準確性與可靠性。
分佈式事務介紹
接下來爲你們介紹業界常見的事務處理模式,包括兩階段提交、三階段提交、Sagas長事務、補償模式、可靠事件模式(本地事件表、外部事件表)、可靠事件模式(非事務消息、事務消息)、TCC等。不一樣的事務模型支持不一樣的數據一致性。若是讀者對這幾種分佈式事務比較熟悉,能夠直接參考下圖並結合自身業務需求選擇合適的事務模型。
1、兩階段提交、三階段提交
這種分佈式事務解決方案目前在各類技術平臺上已經比較成熟:JavaEE架構下面的JTA事務(各應用服務器均提供了實現,tomcat除外)。
目前兩階段提交、三階段提交存在以下的侷限性,並不適合在微服務架構體系下使用:
1)全部的操做必須是事務性資源(好比數據庫、消息隊列、EJB組件等),存在使用侷限性(微服務架構下多數使用HTTP協議),比較適合傳統的單體應用;
2)因爲是強一致性,資源須要在事務內部等待,性能影響較大,吞吐率不高,不適合高併發與高性能的業務場景;
2、Sagas長事務
在Sagas事務模型中,一個長事務是由一個預先定義好執行順序的子事務集合和他們對應的補償子事務集合組成的。典型的一個完整的交易由T一、T二、......、Tn等多個業務活動組成,每一個業務活動能夠是本地操做、或者是遠程操做,全部的業務活動在Sagas事務下要麼所有成功,要麼所有回滾,不存在中間狀態。
Sagas事務模型的實現機制:
1)每一個業務活動都是一個原子操做;
2)每一個業務活動均提供正反操做;
3)任何一個業務活動發生錯誤,按照執行的反順序,實時執行反操做,進行事務回滾;
4)回滾失敗狀況下,須要記錄待衝正事務日誌,經過重試策略進行重試;
5)衝正重試依然失敗的場景,提供定時衝正服務器,對回滾失敗的業務進行定時衝正;
6)定時衝正依然失敗的業務,等待人工干預;
Sagas長事務模型支持對數據一致性要求比較高的場景比較適用,因爲採用了補償的機制,每一個原子操做都是先執行任務,避免了長時間的資源鎖定,能作到實時釋放資源,性能相對有保障。
Sagas長事務方式若是由業務去實現,複雜度與難度並存。在咱們實際使用過程當中,開發了一套支持Sagas事務模型的框架來支撐業務快速交付。
開發人員:業務只須要進行交易編排,每一個原子操做提供正反交易;
配置人員:能夠針對異常類型設定事務回滾策略(哪些異常歸入事務管理、哪些異常不歸入事務管理);每一個原子操做的流水是否持久化(爲了避免同性能能夠支持緩存、DB、以及擴展其它持久化方式);以及衝正選項配置(重試次數、超時時間、是否實時衝正、定時衝正等);
Sagas事務框架:提供事務保障機制,負責原子操做的流水落地,原子操做的執行順序,提供實時衝正、定時衝正、事務攔截器等基礎能力;
Sagas框架的核心是IBusinessActivity、IAtomicAction。IBusinessActivity完成原子活動的enlist()、delist()、prepare()、commit()、rollback()等操做;IAtomicAction主要完成對狀態上下文、正反操做執行。
限於文章篇幅,本文不對具體實現作詳述;後面找時間能夠詳細介紹基於Sagas長事務模型具體的實現框架。
Sagas長事務須要交易提供反操做,支持事務的強一致性,因爲沒有在整個事務週期內鎖定資源,對性能影響較小,適合對數據要求比較高的場景中使用。
3、補償模式
Sagas長事務模型本質上是補償機制的複雜實現,若是實際業務場景上不須要複雜的Sagas事務框架支撐,能夠在業務中實現簡單的補償模式。補償過程每每也一樣須要實現最終一致性,須要保證取消服務至少被調用一次和取消服務必須實現冪等性。補償模式能夠參見同事田向陽的技術文章《微服務架構下數據一致性保證(三)》(相關文章:微服務架構下數據一致性保障(一) 微服務架構下數字一致性保證(二))
補償機制不推薦在複雜場景(須要多個交易的編排)下使用,優勢是很是容易提供回滾,並且依賴的服務也很是少,與Sagas長事務比較來看,使用起來更簡便;缺點是會形成代碼量龐大,耦合性高,對應沒法提供反操做的交易不適合。
4、可靠時間模式
(本地事件表、外地事件表)
可靠事件模式屬於事件驅動架構,當某件重要事情發生時,例如更新一個業務實體,微服務會向消息代理髮佈一個事件。消息代理會向訂閱事件的微服務推送事件,當訂閱這些事件的微服務接收此事件時,就能夠完成本身的業務,也可能會引起更多的事件發佈。
可靠事件模式在於保證可靠事件投遞和避免重複消費,靠事件投遞定義爲:
1)每一個服務原子性的業務操做和發佈事件;
2)消息代理確保事件傳遞至少一次;避免重複消費要求服務實現冪等性。
基於事件模式,須要重點考慮的是事件的可靠到達,在咱們產品實際支持過程當中,一般有本地事件表、外部事件表兩種模式:
一、本地事件表方法將事件和業務數據保存在同一個數據庫中,使用一個額外的「事件恢復」服務來恢復事件,由本地事務保證更新業務和發佈事件的原子性。考慮到事件恢復可能會有必定的延時,服務在完成本地事務後可當即向消息代理髮佈一個事件。
1)微服務在同一個本地事務中記錄業務數據和事件;
2)微服務實時發佈一個事件當即通知關聯的業務服務,若是事件發佈成功當即刪除記錄的事件;
3)事件恢復服務定時從事件表中恢復未發佈成功的事件,從新發布,從新發布成功才刪除記錄的事件;
其中第2條的操做主要是爲了增長髮布事件的實時性,由第三條保證事件必定被髮布。
本地事件表方式業務系統和事件系統耦合比較緊密,額外的事件數據庫操做也會給數據庫帶來額外的壓力,可能成爲瓶頸。
二、外部事件表方法將事件持久化到外部的事件系統,事件系統需提供實時事件服務以接受微服務發佈事件,同時事件系統還須要提供事件恢復服務來確認和恢復事件。
1)業務服務在事務提交前,經過實時事件服務向事件系統請求發送事件,事件系統只記錄事件並不真正發送;
2)業務服務在提交後,經過實時事件服務向事件系統確認發送,事件獲得確認後,事件系統才真正發佈事件到消息代理;
3)業務服務在業務回滾時,經過實時事件向事件系統取消事件;
4)若是業務服務在發送確認或取消以前中止服務了怎麼辦呢?事件系統的事件恢復服務會按期找到未確認發送的事件向業務服務查詢狀態,根據業務服務返回的狀態決定事件是要發佈仍是取消;
該方式將業務系統和事件系統獨立解耦,均可以獨立伸縮。可是這種方式須要一次額外的發送操做,而且須要發佈者提供額外的查詢接口。
基於可靠事件的事務保障模式能夠有不少的變種實現,好比對消息可靠性不高的話,有以下作法:
1)將本地表的方式換作緩存方式;
爲了提升消息投遞的效率,能夠:
2)屢次消息合併投遞模式;
爲了提供強一致性的事務保障,甚至能夠採用:
3)本地消息表持久化(保障發方法消息可靠落地)+遠程消息表持久化(保障接收方消息可靠落地)結合的模式。
在咱們的流程產品中針對業務和流程的分佈式事務解決方案就採用了屢次消息合併投遞+本地緩存+遠程消息表持久化的模式,接下來爲你們介紹具體的使用方式。
使用場景
在實際業務項目中一般採用業務與流程分佈式部署的模式,業務系統經過遠程接口訪問流程引擎,業務數據同流程數據存放到各自的數據庫中。
在這種場景中,若是業務系統的流程操做和業務操做交叉在一塊兒,當流程操做成功,而業務操做失敗時,就會形成業務回滾,而流程在引擎端已經建立,致使業務系統和流程引擎狀態不一致。
在業務應用中對一個事務中的流程操做採用本地緩存+批量投遞+遠程落地的模式(若是須要在客戶端確保消息可靠性,能夠將本地緩存換成本地表的方式);在流程引擎端在消息投遞來以後,作了消息表落地的工做,保障可靠執行。在咱們流程產品中流程引擎對外提供的客戶端提供了統一的分佈式事務API,和使用傳統本地事務同樣進行操做,保證了透明性,簡化開發人員的複雜度。分佈式事務API支持兩種協議模式:
一、http+二進制序列化的模式
二、WebService模式
後續咱們會增長Restful風格的接口。
可靠事件模式在互聯網公司中有着較大規模的應用,該方式適合的業務場景很是普遍,並且可以作到數據的最終一致性,缺點是該模式實現難度較大,依賴數據庫實現可靠性,在高併發場景下可能存在性能瓶頸,須要在公司層面搭建一套標準的可靠事件框架來支撐。
5、可靠事件模式
(非事務消息、事務消息)
可靠事件模式的事件通知能夠採用消息的模式來實現,其實現原理和本地事件表、外部事件表一致,本文就不在詳述。目前經常使用的消息框架ActiveMQ、RabbitMQ、Kafka、RocketMQ能夠用來做爲消息投遞的渠道。注意:Kafka一般不適合,由於Kafka的設計存在丟消息的場景。
目前市面上支持事務的消息產品比較少,RocketMQ雖然實現了可靠的事務模式,但並無開源出來、沒有開源出來、沒有開源出來,順便說一下國內的開源有太多須要改進的空間(關鍵點不開源,開源後沒有持續的投入)。
6、TCC模式
一個完整的TCC業務由一個主業務服務和若干個從業務服務組成,主業務服務發起並完成整個業務活動,TCC模式要求從服務提供三個接口:Try、Confirm、Cancel。·
1) Try:完成全部業務檢查
預留必須業務資源
2) Confirm:真正執行業務
不做任何業務檢查;只使用Try階段預留的業務資源;Confirm操做知足冪等性;
3) Cancel:
釋放Try階段預留的業務資源;Cancel操做知足冪等性;
整個TCC業務分紅兩個階段完成:
第一階段:主業務服務分別調用全部從業務的try操做,並在活動管理器中登記全部從業務服務。當全部從業務服務的try操做都調用成功或者某個從業務服務的try操做失敗,進入第二階段。
第二階段:活動管理器根據第一階段的執行結果來執行confirm或cancel操做。若是第一階段全部try操做都成功,則活動管理器調用全部從業務活動的confirm操做。不然調用全部從業務服務的cancel操做。
TCC模式的詳細描述能夠參見同事田向陽的技術文章《微服務架構下數據一致性保證(三)》
須要注意的是第二階段confirm或cancel操做自己也是知足最終一致性的過程,在調用confirm或cancel的時候也可能由於某種緣由(好比網絡)致使調用失敗,因此須要活動管理支持重試的能力,同時這也就要求confirm和cancel操做具備冪等性。
總結
六種分佈式事務的實現模式從數據一致性、事務級別、吞吐量、實現的複雜度各有優劣,下圖爲你們提供選擇依據。
站在架構設計的角度,針對數據一致性須要把業務因素考慮進來,這有利於團隊在技術上做出更合理的選擇。根據具體業務場景,評估出業務對事務的優先級,更有利於做出架構上的取捨。咱們常常接觸的證券、金融、支付等行業,對數據一致性要求極高,須要嚴格的實時保證要求;但對於基於社交類的應用場景,能夠採用局部實時一致,最終全局一致的能力。所以你們在實踐過程當中,必定要把技術與業務結合,選擇適合自身業務的技術方案。數據庫