前言 這是一個(gè)開(kāi)撕的話(huà)題,我經(jīng)歷過(guò)太多的關(guān)于分布式事務(wù)的需求:“有沒(méi)有簡(jiǎn)單的方案,像使用數(shù)據(jù)庫(kù)事務(wù)那樣,解決分布式數(shù)據(jù)一致性的問(wèn)題”。特別是微服務(wù)架構(gòu)流行的今天,一次交易需要跨越多個(gè)“服務(wù)”、多個(gè)數(shù)據(jù)庫(kù)來(lái)實(shí)現(xiàn),傳統(tǒng)的技術(shù)手段,已經(jīng)無(wú)法應(yīng)對(duì)和滿(mǎn)足微服務(wù)情況下這些復(fù)雜的場(chǎng)景了。 談到分布式事務(wù),必須先把CAP拿出來(lái)說(shuō)說(shuō)事……,當(dāng)然還有BASE…… 從架構(gòu)的角度來(lái)看,業(yè)務(wù)拆分(數(shù)據(jù)分區(qū))、數(shù)據(jù)一致性、性能(可用性)永遠(yuǎn)是個(gè)平衡的藝術(shù):
在計(jì)算機(jī)世界里,為了解決一件事情,另外的問(wèn)題就會(huì)接踵而至,從另一個(gè)層面印證了IT架構(gòu)永遠(yuǎn)是一種平衡的藝術(shù)。 “BASE”其核心思想是根據(jù)業(yè)務(wù)特點(diǎn),采用適當(dāng)?shù)姆绞絹?lái)使系統(tǒng)達(dá)到最終一致性(Eventual consistency);在互聯(lián)網(wǎng)領(lǐng)域,通常需要犧牲強(qiáng)一致性來(lái)?yè)Q取系統(tǒng)的高可用性,只需要保證數(shù)據(jù)的“最終一致”,只是這個(gè)最終時(shí)間需要在用戶(hù)可以接受的范圍內(nèi);但在金融相關(guān)的交易領(lǐng)域,仍然需要采用強(qiáng)一致性的方式來(lái)保障交易的準(zhǔn)確性與可靠性。 接下來(lái)為大家介紹業(yè)界常見(jiàn)的事務(wù)處理模式,包括兩階段提交、三階段提交、Sagas長(zhǎng)事務(wù)、補(bǔ)償模式、可靠事件模式(本地事件表、外部事件表)、可靠事件模式(非事務(wù)消息、事務(wù)消息)、TCC等。不同的事務(wù)模型支持不同的數(shù)據(jù)一致性。如果讀者對(duì)這幾種分布式事務(wù)比較熟悉,可以直接參考下圖并結(jié)合自身業(yè)務(wù)需求選擇合適的事務(wù)模型。 兩階段提交、三階段提交 這種分布式事務(wù)解決方案目前在各種技術(shù)平臺(tái)上已經(jīng)比較成熟:JavaEE架構(gòu)下面的JTA事務(wù)(各應(yīng)用服務(wù)器均提供了實(shí)現(xiàn),Tomcat除外)。 但目前兩階段提交、三階段提交存在如下的局限性,并不適合在微服務(wù)架構(gòu)體系下使用:
Sagas長(zhǎng)事務(wù) 在Sagas事務(wù)模型中,一個(gè)長(zhǎng)事務(wù)是由一個(gè)預(yù)先定義好執(zhí)行順序的子事務(wù)集合和他們對(duì)應(yīng)的補(bǔ)償子事務(wù)集合組成的。典型的一個(gè)完整的交易由T1、T2、……、Tn等多個(gè)業(yè)務(wù)活動(dòng)組成,每個(gè)業(yè)務(wù)活動(dòng)可以是本地操作、或者是遠(yuǎn)程操作,所有的業(yè)務(wù)活動(dòng)在Sagas事務(wù)下要么全部成功,要么全部回滾,不存在中間狀態(tài)。 Sagas事務(wù)模型的實(shí)現(xiàn)機(jī)制:
Sagas長(zhǎng)事務(wù)模型支持對(duì)數(shù)據(jù)一致性要求比較高的場(chǎng)景比較適用,由于采用了補(bǔ)償?shù)臋C(jī)制,每個(gè)原子操作都是先執(zhí)行任務(wù),避免了長(zhǎng)時(shí)間的資源鎖定,能做到實(shí)時(shí)釋放資源,性能相對(duì)有保障。 Sagas長(zhǎng)事務(wù)方式如果由業(yè)務(wù)去實(shí)現(xiàn),復(fù)雜度與難度并存。在我們實(shí)際使用過(guò)程中,開(kāi)發(fā)了一套支持Sagas事務(wù)模型的框架來(lái)支撐業(yè)務(wù)快速交付。 開(kāi)發(fā)人員:業(yè)務(wù)只需要進(jìn)行交易編排,每個(gè)原子操作提供正反交易; 配置人員:可以針對(duì)異常類(lèi)型設(shè)定事務(wù)回滾策略(哪些異常納入事務(wù)管理、哪些異常不納入事務(wù)管理);每個(gè)原子操作的流水是否持久化(為了不同性能可以支持緩存、DB、以及擴(kuò)展其它持久化方式);以及沖正選項(xiàng)配置(重試次數(shù)、超時(shí)時(shí)間、是否實(shí)時(shí)沖正、定時(shí)沖正等); Sagas事務(wù)框架:提供事務(wù)保障機(jī)制,負(fù)責(zé)原子操作的流水落地,原子操作的執(zhí)行順序,提供實(shí)時(shí)沖正、定時(shí)沖正、事務(wù)攔截器等基礎(chǔ)能力; Sagas框架的核心是IBusinessActivity、IAtomicAction。IBusinessActivity完成原子活動(dòng)的enlist()、delist()、prepare()、commit()、rollback()等操作;IAtomicAction主要完成對(duì)狀態(tài)上下文、正反操作執(zhí)行。 限于文章篇幅,本文不對(duì)具體實(shí)現(xiàn)做詳述;后面找時(shí)間可以詳細(xì)介紹基于Sagas長(zhǎng)事務(wù)模型具體的實(shí)現(xiàn)框架。Sagas長(zhǎng)事務(wù)需要交易提供反操作,支持事務(wù)的強(qiáng)一致性,由于沒(méi)有在整個(gè)事務(wù)周期內(nèi)鎖定資源,對(duì)性能影響較小,適合對(duì)數(shù)據(jù)要求比較高的場(chǎng)景中使用。 補(bǔ)償模式 Sagas長(zhǎng)事務(wù)模型本質(zhì)上是補(bǔ)償機(jī)制的復(fù)雜實(shí)現(xiàn),如果實(shí)際業(yè)務(wù)場(chǎng)景上不需要復(fù)雜的Sagas事務(wù)框架支撐,可以在業(yè)務(wù)中實(shí)現(xiàn)簡(jiǎn)單的補(bǔ)償模式。補(bǔ)償過(guò)程往往也同樣需要實(shí)現(xiàn)最終一致性,需要保證取消服務(wù)至少被調(diào)用一次和取消服務(wù)必須實(shí)現(xiàn)冪等性。補(bǔ)償模式可以參見(jiàn)同事田向陽(yáng)的技術(shù)文章《微服務(wù)架構(gòu)下數(shù)據(jù)一致性保證(三)》http:///3TVJaB 補(bǔ)償機(jī)制不推薦在復(fù)雜場(chǎng)景(需要多個(gè)交易的編排)下使用,優(yōu)點(diǎn)是非常容易提供回滾,而且依賴(lài)的服務(wù)也非常少,與Sagas長(zhǎng)事務(wù)比較來(lái)看,使用起來(lái)更簡(jiǎn)便;缺點(diǎn)是會(huì)造成代碼量龐大,耦合性高,對(duì)應(yīng)無(wú)法提供反操作的交易不適合。 可靠事件模式(本地事件表、外地事件表) 可靠事件模式屬于事件驅(qū)動(dòng)架構(gòu),當(dāng)某件重要事情發(fā)生時(shí),例如更新一個(gè)業(yè)務(wù)實(shí)體,微服務(wù)會(huì)向消息代理發(fā)布一個(gè)事件。消息代理會(huì)向訂閱事件的微服務(wù)推送事件,當(dāng)訂閱這些事件的微服務(wù)接收此事件時(shí),就可以完成自己的業(yè)務(wù),也可能會(huì)引發(fā)更多的事件發(fā)布。 可靠事件模式在于保證可靠事件投遞和避免重復(fù)消費(fèi),靠事件投遞定義為:
基于事件模式,需要重點(diǎn)考慮的是事件的可靠到達(dá),在我們產(chǎn)品實(shí)際支持過(guò)程中,通常有本地事件表、外部事件表兩種模式: 1、本地事件表方法將事件和業(yè)務(wù)數(shù)據(jù)保存在同一個(gè)數(shù)據(jù)庫(kù)中,使用一個(gè)額外的“事件恢復(fù)”服務(wù)來(lái)恢復(fù)事件,由本地事務(wù)保證更新業(yè)務(wù)和發(fā)布事件的原子性??紤]到事件恢復(fù)可能會(huì)有一定的延時(shí),服務(wù)在完成本地事務(wù)后可立即向消息代理發(fā)布一個(gè)事件。
其中第2條的操作主要是為了增加發(fā)布事件的實(shí)時(shí)性,由第三條保證事件一定被發(fā)布。本地事件表方式業(yè)務(wù)系統(tǒng)和事件系統(tǒng)耦合比較緊密,額外的事件數(shù)據(jù)庫(kù)操作也會(huì)給數(shù)據(jù)庫(kù)帶來(lái)額外的壓力,可能成為瓶頸。 2、外部事件表方法將事件持久化到外部的事件系統(tǒng),事件系統(tǒng)需提供實(shí)時(shí)事件服務(wù)以接受微服務(wù)發(fā)布事件,同時(shí)事件系統(tǒng)還需要提供事件恢復(fù)服務(wù)來(lái)確認(rèn)和恢復(fù)事件。
該方式將業(yè)務(wù)系統(tǒng)和事件系統(tǒng)獨(dú)立解耦,都可以獨(dú)立伸縮。但是這種方式需要一次額外的發(fā)送操作,并且需要發(fā)布者提供額外的查詢(xún)接口。 基于可靠事件的事務(wù)保障模式可以有很多的變種實(shí)現(xiàn),比如對(duì)消息可靠性不高的話(huà),可以將本地表的方式換做緩存方式。為了提高消息投遞的效率,可以將多次消息合并為投遞模式。為了提供強(qiáng)一致性的事務(wù)保障,甚至可以將本地消息表持久化(保障發(fā)方法消息可靠落地)+遠(yuǎn)程消息表持久化(保障接收方消息可靠落地)結(jié)合的模式。 在我們的流程產(chǎn)品中針對(duì)業(yè)務(wù)和流程的分布式事務(wù)解決方案就采用了多次消息合并投遞+本地緩存+遠(yuǎn)程消息表持久化的模式,接下來(lái)為大家介紹具體的使用方式。 使用場(chǎng)景 在實(shí)際業(yè)務(wù)項(xiàng)目中通常采用業(yè)務(wù)與流程分布式部署的模式,業(yè)務(wù)系統(tǒng)通過(guò)遠(yuǎn)程接口訪(fǎng)問(wèn)流程引擎,業(yè)務(wù)數(shù)據(jù)同流程數(shù)據(jù)存放到各自的數(shù)據(jù)庫(kù)中。 在這種場(chǎng)景中,如果業(yè)務(wù)系統(tǒng)的流程操作和業(yè)務(wù)操作交叉在一起,當(dāng)流程操作成功,而業(yè)務(wù)操作失敗時(shí),就會(huì)造成業(yè)務(wù)回滾,而流程在引擎端已經(jīng)創(chuàng)建,導(dǎo)致業(yè)務(wù)系統(tǒng)和流程引擎狀態(tài)不一致。 在業(yè)務(wù)應(yīng)用中對(duì)一個(gè)事務(wù)中的流程操作采用本地緩存+批量投遞+遠(yuǎn)程落地的模式(如果需要在客戶(hù)端確保消息可靠性,可以將本地緩存換成本地表的方式);在流程引擎端在消息投遞來(lái)之后,做了消息表落地的工作,保障可靠執(zhí)行。在我們流程產(chǎn)品中流程引擎對(duì)外提供的客戶(hù)端提供了統(tǒng)一的分布式事務(wù)API,和使用傳統(tǒng)本地事務(wù)一樣進(jìn)行操作,保證了透明性,簡(jiǎn)化開(kāi)發(fā)人員的復(fù)雜度。分布式事務(wù)API支持兩種協(xié)議模式:
后續(xù)我們會(huì)增加Restful風(fēng)格的接口。 可靠事件模式在互聯(lián)網(wǎng)公司中有著較大規(guī)模的應(yīng)用,該方式適合的業(yè)務(wù)場(chǎng)景非常廣泛,而且能夠做到數(shù)據(jù)的最終一致性,缺點(diǎn)是該模式實(shí)現(xiàn)難度較大,依賴(lài)數(shù)據(jù)庫(kù)實(shí)現(xiàn)可靠性,在高并發(fā)場(chǎng)景下可能存在性能瓶頸,需要在公司層面搭建一套標(biāo)準(zhǔn)的可靠事件框架來(lái)支撐。 可靠事件模式(非事務(wù)消息、事務(wù)消息) 可靠事件模式的事件通知可以采用消息的模式來(lái)實(shí)現(xiàn),其實(shí)現(xiàn)原理和本地事件表、外部事件表一致,本文就不在詳述。目前常用的消息框架ActiveMQ、RabbitMQ、Kafka、RocketMQ可以用來(lái)作為消息投遞的渠道。注意:Kafka通常不適合,因?yàn)镵afka的設(shè)計(jì)存在丟消息的場(chǎng)景。 目前市面上支持事務(wù)的消息產(chǎn)品比較少,RocketMQ雖然實(shí)現(xiàn)了可靠的事務(wù)模式,但并沒(méi)有開(kāi)源出來(lái)、沒(méi)有開(kāi)源出來(lái)、沒(méi)有開(kāi)源出來(lái),順便說(shuō)一下國(guó)內(nèi)的開(kāi)源有太多需要改進(jìn)的空間(關(guān)鍵點(diǎn)不開(kāi)源,開(kāi)源后沒(méi)有持續(xù)的投入)。 TCC模式 一個(gè)完整的TCC業(yè)務(wù)由一個(gè)主業(yè)務(wù)服務(wù)和若干個(gè)從業(yè)務(wù)服務(wù)組成,主業(yè)務(wù)服務(wù)發(fā)起并完成整個(gè)業(yè)務(wù)活動(dòng),TCC模式要求從服務(wù)提供三個(gè)接口:Try、Confirm、Cancel。
整個(gè)TCC業(yè)務(wù)分成兩個(gè)階段完成: 第一階段:主業(yè)務(wù)服務(wù)分別調(diào)用所有從業(yè)務(wù)的try操作,并在活動(dòng)管理器中登記所有從業(yè)務(wù)服務(wù)。當(dāng)所有從業(yè)務(wù)服務(wù)的try操作都調(diào)用成功或者某個(gè)從業(yè)務(wù)服務(wù)的try操作失敗,進(jìn)入第二階段。 第二階段:活動(dòng)管理器根據(jù)第一階段的執(zhí)行結(jié)果來(lái)執(zhí)行confirm或cancel操作。如果第一階段所有try操作都成功,則活動(dòng)管理器調(diào)用所有從業(yè)務(wù)活動(dòng)的confirm操作。否則調(diào)用所有從業(yè)務(wù)服務(wù)的cancel操作。 TCC模式的詳細(xì)描述可以參見(jiàn)同事田向陽(yáng)的技術(shù)文章《微服務(wù)架構(gòu)下數(shù)據(jù)一致性保證(三)》http:///3TVJaB。 需要注意的是第二階段confirm或cancel操作本身也是滿(mǎn)足最終一致性的過(guò)程,在調(diào)用confirm或cancel的時(shí)候也可能因?yàn)槟撤N原因(比如網(wǎng)絡(luò))導(dǎo)致調(diào)用失敗,所以需要活動(dòng)管理支持重試的能力,同時(shí)這也就要求confirm和cancel操作具有冪等性。 總結(jié) 六種分布式事務(wù)的實(shí)現(xiàn)模式從數(shù)據(jù)一致性、事務(wù)級(jí)別、吞吐量、實(shí)現(xiàn)的復(fù)雜度各有優(yōu)劣,下圖為大家提供選擇依據(jù)。 站在架構(gòu)設(shè)計(jì)的角度,針對(duì)數(shù)據(jù)一致性需要把業(yè)務(wù)因素考慮進(jìn)來(lái),這有利于團(tuán)隊(duì)在技術(shù)上作出更合理的選擇。根據(jù)具體業(yè)務(wù)場(chǎng)景,評(píng)估出業(yè)務(wù)對(duì)事務(wù)的優(yōu)先級(jí),更有利于作出架構(gòu)上的取舍。我們經(jīng)常接觸的證券、金融、支付等行業(yè),對(duì)數(shù)據(jù)一致性要求極高,需要嚴(yán)格的實(shí)時(shí)保證要求;但對(duì)于基于社交類(lèi)的應(yīng)用場(chǎng)景,可以采用局部實(shí)時(shí)一致,最終全局一致的能力。因此大家在實(shí)踐過(guò)程中,一定要把技術(shù)與業(yè)務(wù)結(jié)合,選擇適合自身業(yè)務(wù)的技術(shù)方案。 ▽
喜歡我們的會(huì)點(diǎn)贊,愛(ài)我們的會(huì)分享!
|
|
來(lái)自: openlabzeng > 《待分類(lèi)》