標籤:
from: http://mp.weixin.qq.com/s?__biz=MzA5Nzc4OTA1Mw==&mid=2659598134&idx=1&sn=f5f73354d162a7561b3d73c204a4d1f5&scene=0#wechat_redirect
這是一個開撕的話題,我經曆過太多的關於分散式交易的需求:“有沒有簡單的方案,像使用資料庫事務那樣,解決分布式資料一致性的問題”。特別是微服務架構流行的今天,一次交易需要跨越多個“服務”、多個資料庫來實現,傳統的技術手段,已經無法應對和滿足微服務情況下這些複雜的情境了。針對微服務下的交易業務如何保障資料一致性,本文盡量做到理論結合實踐,將我們在實際產品中用到的分散式交易實現機制,和大家扒一扒,希望能幫到各位。
談到分散式交易,必須先把CAP拿出來說說事……,當然還有BASE……
從架構的角度來看,業務拆分(資料分區)、資料一致性、效能(可用性)永遠是個平衡的藝術:
在電腦世界裡,為瞭解決一件事情,另外的問題就會接踵而至,從另一個層面印證了IT架構永遠是一種平衡的藝術。
“BASE”其核心思想是根據業務特點,採用適當的方式來使系統達到最終一致性(Eventual consistency);在互連網領域,通常需要犧牲強一致性來換取系統的高可用性,只需要保證資料的“最終一致”,只是這個最終時間需要在使用者可以接受的範圍內;但在金融相關的交易領域,仍然需要採用強一致性的方式來保障交易的準確性與可靠性。
接下來為大家介紹業界常見的交易處理模式,包括兩階段交易認可、三階段提交、Sagas長事務、補償模式、可靠事件模式(本地事件表、外來事件表)、可靠事件模式(非事務訊息、事務訊息)、TCC等。不同的事務模型支援不同的資料一致性。如果讀者對這幾種分散式交易比較熟悉,可以直接參考並結合自身業務需求選擇合適的事務模型。
兩階段交易認可、三階段提交
這種分散式交易解決方案目前在各種技術平台上已經比較成熟:JavaEE架構下面的JTA事務(各應用伺服器均提供了實現,Tomcat除外)。
但目前兩階段交易認可、三階段提交存在如下的局限性,並不適合在微服務架構體系下使用:
Sagas長事務
在Sagas事務模型中,一個長事務是由一個預先定義好執行順序的子事務集合和他們對應的補償子事務集合組成的。典型的一個完整的交易由T1、T2、……、Tn等多個商務活動組成,每個商務活動可以是本地操作、或者是遠程操作,所有的商務活動在Sagas事務下要麼全部成功,要麼全部復原,不存在中間狀態。
Sagas事務模型的實現機制:
每個商務活動都是一個原子操作;
每個商務活動均提供正反操作;
任何一個商務活動發生錯誤,按照執行的反順序,即時執行反操作,進行交易回復;
復原失敗情況下,需要記錄待沖正交易記錄,通過重試策略進行重試;
沖正重試依然失敗的情境,提供定時沖正伺服器,對復原失敗的業務進行定時沖正;
定時沖正依然失敗的業務,等待人工幹預;
Sagas長事務模型支援對資料一致性要求比較高的情境比較適用,由於採用了補償的機制,每個原子操作都是先執行任務,避免了長時間的資源鎖定,能做到即時釋放資源,效能相對有保障。
Sagas長事務方式如果由業務去實現,複雜度與難度並存。在我們實際使用過程中,開發了一套支援Sagas事務模型的架構來支撐業務快速交付。
開發人員:業務只需要進行交易編排,每個原子操作提供正反交易;
配置人員:可以針對異常類型設定交易回復策略(哪些異常納入交易管理、哪些異常不納入交易管理);每個原子操作的流水是否持久化(為了不同效能可以支援緩衝、DB、以及擴充其它持久化方式);以及沖正選項配置(重試次數、逾時時間、是否即時沖正、定時沖正等);
Sagas事務架構:提供事務保障機制,負責原子操作的流水落地,原子操作的執行順序,提供即時沖正、定時沖正、事務攔截器等基礎能力;
Sagas架構的核心是IBusinessActivity、IAtomicAction。IBusinessActivity完成原子活動的enlist()、delist()、prepare()、commit()、rollback()等操作;IAtomicAction主要完成對狀態上下文、正反操作執行。
限於文章篇幅,本文不對具體實現做詳述;後面找時間可以詳細介紹基於Sagas長事務模型具體的實現架構。Sagas長事務需要交易提供反操作,支援事務的強一致性,由於沒有在整個事務周期內鎖定資源,對效能影響較小,適合對資料要求比較高的情境中使用。
補償模式
Sagas長事務模型本質上是補償機制的複雜實現,如果實際業務情境上不需要複雜的Sagas事務架構支撐,可以在業務中實現簡單的補償模式。補償過程往往也同樣需要實現最終一致性,需要保證取消服務至少被調用一次和取消服務必須實現等冪性。補償模式可以參見同事田向陽的技術文章《微服務架構下資料一致性保證(三)》http://dwz.cn/3TVJaB
補償機制不推薦在複雜情境(需要多個交易的編排)下使用,優點是非常容易提供復原,而且依賴的服務也非常少,與Sagas長事務比較來看,使用起來更簡便;缺點是會造成代碼量龐大,耦合性高,對應無法提供反操作的交易不適合。
可靠事件模式(本地事件表、外地事件表)
可靠事件模式屬於事件驅動架構,當某件重要事情發生時,例如更新一個業務實體,微服務會向訊息代理髮布一個事件。訊息代理會向訂閱事件的微服務推送事件,當訂閱這些事件的微服務接收此事件時,就可以完成自己的業務,也可能會引發更多的事件發布。
可靠事件模式在於保證可靠事件投遞和避免重複消費,靠事件投遞定義為:
基於事件模式,需要重點考慮的是事件的可靠到達,在我們產品實際支援過程中,通常有本地事件表、外來事件表兩種模式:
1. 本地事件表方法將事件和業務資料儲存在同一個資料庫中,使用一個額外的“事件恢複”服務來恢複事件,由本地事務保證更新業務和發布事件的原子性。考慮到事件恢複可能會有一定的延時,服務在完成本地事務後可立即向訊息代理髮布一個事件。
微服務在同一個本地事務中記錄業務資料和事件;
微服務即時發布一個事件立即通知關聯的商務服務,如果事件發布成功立即刪除記錄的事件;
事件恢複服務定時從事件表中恢複未發布成功的事件,重新發布,重新發布成功才刪除記錄的事件;
其中第2條的操作主要是為了增加發布事件的即時性,由第三條保證事件一定被發布。本地事件表方式業務系統和事件系統耦合比較緊密,額外的事件數目據庫操作也會給資料庫帶來額外的壓力,可能成為瓶頸。
2. 外來事件表方法將事件持久化到外部的事件系統,事件系統需提供即時事件服務以接受微服務發布事件,同時事件系統還需要提供事件恢複服務來確認和恢複事件。
商務服務在事務提交前,通過即時事件服務向事件系統請求發送事件,事件系統只記錄事件並不真正發送;
商務服務在提交後,通過即時事件服務向事件系統確認發送,事件得到確認後,事件系統才真正發布事件到訊息代理;
商務服務在業務復原時,通過即時事件向事件系統取消事件;
如果商務服務在發送確認或取消之前停止服務了怎麼辦呢?事件系統的事件恢複服務會定期找到未確認發送的事件向商務服務查詢狀態,根據商務服務返回的狀態決定事件是要發布還是取消;
該方式將業務系統和事件系統獨立解耦,都可以獨立伸縮。但是這種方式需要一次額外的發送操作,並且需要發行者提供額外的查詢介面。
基於可靠事件的事務保障模式可以有很多的變種實現,比如對訊息可靠性不高的話,可以將本地表的方式換做緩衝方式。為了提高訊息投遞的效率,可以將多次訊息合并為投遞模式。為了提供強一致性的事務保障,甚至可以將本地訊息表持久化(保障發方法訊息可靠落地)+遠程訊息表持久化(保障接收方訊息可靠落地)結合的模式。
在我們的流程產品中針對業務和流程的分散式交易解決方案就採用了多次訊息合并投遞+本機快取+遠程訊息表持久化的模式,接下來為大家介紹具體的使用方式。
使用情境
在實際商務專案中通常採用業務與流程分布式部署的模式,業務系統通過遠程介面訪問流程引擎,業務資料同流程資料存放到各自的資料庫中。
在這種情境中,如果業務系統的流程操作和業務操作交叉在一起,當流程操作成功,而業務操作失敗時,就會造成業務復原,而流程在引擎端已經建立,導致業務系統和流程引擎狀態不一致。
在業務應用中對一個事務中的流程操作採用本機快取+批量投遞+遠程落地的模式(如果需要在用戶端確保訊息可靠性,可以將本機快取換成本地表的方式);在流程引擎端在訊息投遞來之後,做了訊息表落地的工作,保障可靠執行。在我們流程產品中流程引擎對外提供的用戶端提供了統一的分散式交易API,和使用傳統本地事務一樣進行操作,保證了透明性,簡化開發人員的複雜度。分散式交易API支援兩種協議模式:
HTTP + 二進位序列化的模式
WebService模式
後續我們會增加Restful風格的介面。
可靠事件模式在互連網公司中有著較大規模的應用,該方式適合的業務情境非常廣泛,而且能夠做到資料的最終一致性,缺點是該模式實現難度較大,依賴資料庫實現可靠性,在高並發情境下可能存在效能瓶頸,需要在公司層面搭建一套標準的可靠事件架構來支撐。
可靠事件模式(非事務訊息、事務訊息)
可靠事件模式的事件通知可以採用訊息的模式來實現,其實現原理和本地事件表、外來事件表一致,本文就不在詳述。目前常用的訊息架構ActiveMQ、RabbitMQ、Kafka、RocketMQ可以用來作為訊息投遞的渠道。注意:Kafka通常不適合,因為Kafka的設計存在丟訊息的情境。
目前市面上支援事務的訊息產品比較少,RocketMQ雖然實現了可靠的事務模式,但並沒有開源出來、沒有開源出來、沒有開源出來,順便說一下國內的開源有太多需要改進的空間(關鍵點不開源,開源後沒有持續的投入)。
TCC模式
一個完整的TCC業務由一個主商務服務和若干個從商務服務組成,主商務服務發起並完成整個商務活動,TCC模式要求從服務提供三個介面:Try、Confirm、Cancel。
Try:完成所有業務檢查
預留必須業務資源
Confirm:真正執行業務
不作任何業務檢查;只使用Try階段預留的業務資源;Confirm操作滿足等冪性;
Cancel:
釋放Try階段預留的業務資源;Cancel操作滿足等冪性;
整個TCC業務分成兩個階段完成:
第一階段:主商務服務分別調用所有從業務的try操作,並在Active Manager中登記所有從商務服務。當所有從商務服務的try操作都調用成功或者某個從商務服務的try操作失敗,進入第二階段。
第二階段:Active Manager根據第一階段的執行結果來執行confirm或cancel操作。如果第一階段所有try操作都成功,則Active Manager調用所有從商務活動的confirm操作。否則調用所有從商務服務的cancel操作。
TCC模式的詳細描述可以參見同事田向陽的技術文章《微服務架構下資料一致性保證(三)》http://dwz.cn/3TVJaB。
需要注意的是第二階段confirm或cancel操作本身也是滿足最終一致性的過程,在調用confirm或cancel的時候也可能因為某種原因(比如網路)導致調用失敗,所以需要活動管理支援重試的能力,同時這也就要求confirm和cancel操作具有等冪性。
總結
六種分散式交易的實現模式從資料一致性、事務層級、輸送量、實現的複雜度各有優劣,為大家提供選擇依據。
站在架構設計的角度,針對資料一致性需要把業務因素考慮進來,這有利於團隊在技術上作出更合理的選擇。根據具體業務情境,評估出業務對事務的優先順序,更有利於作出架構上的取捨。我們經常接觸的證券、金融、支付等行業,對資料一致性要求極高,需要嚴格的即時保證要求;但對於基於社交類的應用情境,可以採用局部即時一致,最終全域一致的能力。因此大家在實踐過程中,一定要把技術與業務結合,選擇適合自身業務的技術方案。
作者介紹
劉相,來自普元,十年IT行業經驗,專註於企業軟體平台。在SOA、分散式運算、企業架構設計等領域有一定瞭解。著有《SpringBatch批處理架構》一書。
轉: 分散式交易:不過是在一致性、輸送量和複雜度之間,做一個選擇