框架相關(guān)(2)-- 分布式事務(wù)

分布式事務(wù)解決的用戶最本質(zhì)訴求是什么趋翻?數(shù)據(jù)一致。

大中企業(yè)有一個共同的訴求是數(shù)據(jù)一致盒蟆,幾乎覆蓋到各個行業(yè)踏烙。

比如說零售行業(yè),庫存與出貨的數(shù)據(jù)需要保持一致历等,出貨量與庫存數(shù)據(jù)不匹配讨惩,顯而易見會出問題,拿到訂單卻沒貨了寒屯,或者有貨卻下不了訂單荐捻。

比如說金融行業(yè),轉(zhuǎn)賬數(shù)據(jù)搞錯了寡夹,A扣款了处面,B沒加上,馬上該用戶投訴了菩掏;A沒扣款魂角,B卻加上了,產(chǎn)生資損智绸。又比如從總賬戶中買了基金或颊、股票后余額不對了,等等传于,都會導(dǎo)致嚴(yán)重問題囱挑。

以前多數(shù)企業(yè)的數(shù)據(jù)規(guī)模相對較小,很多操作是單機完成沼溜,數(shù)據(jù)庫本地事務(wù)可以搞定平挑,所以數(shù)據(jù)一致問題不那么明顯。隨著互聯(lián)網(wǎng)技術(shù)快速發(fā)展系草,數(shù)據(jù)規(guī)模增大通熄,分布式系統(tǒng)越來越普及,采用分布式數(shù)據(jù)庫或者跨多個數(shù)據(jù)庫的應(yīng)用在中大規(guī)模企業(yè)普遍存在找都,服務(wù)化也是廣泛應(yīng)用唇辨,由于網(wǎng)絡(luò)的不可靠和機器不可靠,數(shù)據(jù)不一致問題很容易出現(xiàn)能耻。

?

事務(wù)的基本特性:

Atomicity(原子性):是指事務(wù)是一個不可分割的整體赏枚,所有操作要么全做亡驰,要么全不做;只要事務(wù)中有一個操作出錯饿幅,回滾到事務(wù)開始前的狀態(tài)凡辱,那么之前已經(jīng)執(zhí)行的所有操作都是無效的,都應(yīng)該會滾到開始前的狀態(tài)栗恩。

Consistency(一致性):指事務(wù)執(zhí)行前后透乾,數(shù)據(jù)從一個狀態(tài)到另一個狀態(tài)必須是一致的,比如A向B轉(zhuǎn)賬(A磕秤、B的總金額就是一個一致性狀態(tài))乳乌,不可能出現(xiàn)A扣了錢, B卻沒收到的情況市咆。

Isolation(隔離性):多個并發(fā)事務(wù)之間相互隔離钦扭,不能相互干擾。這里的并發(fā)事務(wù)指的是兩個事務(wù)操作了同一份數(shù)據(jù)的情況床绪,要求不能出現(xiàn)臟讀客情、幻讀的情況。常用手段就是通過數(shù)據(jù)庫的相關(guān)鎖機制來保證癞己。

Durablity(持久性):事務(wù)完成后膀斋,對數(shù)據(jù)庫的更改是永久保存的,不能回滾痹雅。


分布式事務(wù)

分布式事務(wù)是為了解決微服務(wù)架構(gòu)(形式都是分布式系統(tǒng))中不同節(jié)點之間的數(shù)據(jù)一致性的問題仰担。這個一致性問題本質(zhì)上解決的也是傳統(tǒng)事務(wù)需要解決的問題,即一個請求在多個微服務(wù)調(diào)用鏈中绩社,所有服務(wù)的數(shù)據(jù)處理要么全部成功摔蓝,要么全部回滾。當(dāng)然分布式事務(wù)問題的形式可能與傳統(tǒng)事務(wù)會有比較大的差異愉耙,但是問題本質(zhì)是一致的贮尉,都是要求解決數(shù)據(jù)的一致性問題,并且滿足事務(wù)的基本特性(ACID)朴沿。

舉個例子猜谚,在一個JVM進程中如果需要同時操作數(shù)據(jù)庫的多條記錄,而這些操作需要在一個事務(wù)中赌渣,那么我們就可以通過數(shù)據(jù)庫提供的事務(wù)機制(一般是數(shù)據(jù)庫鎖)來實現(xiàn)魏铅。而隨著這個JVM進程(應(yīng)用)被拆分成了微服務(wù)架構(gòu),原本一個本地邏輯執(zhí)行單元被分到了多個獨立的微服務(wù)中坚芜,這些微服務(wù)又分別操作不同的數(shù)據(jù)庫和表览芳,服務(wù)之間通過網(wǎng)絡(luò)調(diào)用。

在微服務(wù)中的分布式事務(wù)問題

讓我門想象一下一個傳統(tǒng)的單體應(yīng)用鸿竖,它的業(yè)務(wù)由三個模塊構(gòu)建而成沧竟,他們使用了一個單一本地數(shù)據(jù)源铸敏。很顯然,本地事務(wù)可以保證整個業(yè)務(wù)過程的數(shù)據(jù)一致性屯仗。

微服務(wù)架構(gòu)中一些事情需要被改變搞坝,這三個被上文提及到的模塊搔谴,被設(shè)計為三個不同數(shù)據(jù)源之上的三個服務(wù)魁袜,業(yè)務(wù)過程將由3個服務(wù)的調(diào)用來完成。

此時敦第,每個服務(wù)內(nèi)部的數(shù)據(jù)一致性仍由本地事務(wù)來保證峰弹。而整個業(yè)務(wù)層面的全局?jǐn)?shù)據(jù)一致性要如何保障呢?這就是微服務(wù)架構(gòu)下面臨的芜果,典型的分布式事務(wù)需求:我們需要一個分布式事務(wù)的解決方案保障業(yè)務(wù)全局的數(shù)據(jù)一致性鞠呈。

關(guān)于分布式事務(wù),工程領(lǐng)域主要討論的是強一致性和最終一致性的解決方案右钾。典型方案包括蚁吝,對業(yè)務(wù)無侵入的和對業(yè)務(wù)有侵入的兩類:

業(yè)務(wù)無侵入方案

? ? * 兩階段提交(2PC, Two-phase Commit)、三階段提交(3PC)

業(yè)務(wù)侵入方案

? ? * TCC 補償模式

? ? * 基于消息的最終一致性

?

分布式事務(wù)解決方案

(1)2PC方案——強一致性

基于XA協(xié)議的兩階段提交方案

交易中間件與數(shù)據(jù)庫通過 XA 接口規(guī)范舀射,使用兩階段提交來完成一個全局事務(wù)窘茁, XA 規(guī)范的基礎(chǔ)是兩階段提交協(xié)議。

第一階段是表決階段脆烟,所有參與者都將本事務(wù)能否成功的信息反饋發(fā)給協(xié)調(diào)者山林;第二階段是執(zhí)行階段,協(xié)調(diào)者根據(jù)所有參與者的反饋邢羔,通知所有參與者驼抹,步調(diào)一致地在所有分支上提交或者回滾。

兩階段提交方案應(yīng)用非常廣泛拜鹤,幾乎所有商業(yè)OLTP數(shù)據(jù)庫都支持XA協(xié)議框冀。但是兩階段提交方案鎖定資源時間長,對性能影響很大敏簿,基本不適合解決微服務(wù)事務(wù)問題左驾。

2PC

階段1:請求階段(commit-request phase,或稱表決階段极谊,voting phase)

協(xié)調(diào)者節(jié)點向所有參與者節(jié)點詢問是否可以執(zhí)行提交操作诡右,并開始等待各參與者節(jié)點的響應(yīng)。

參與者節(jié)點執(zhí)行詢問發(fā)起為止的所有事務(wù)操作轻猖,并將Undo信息和Redo信息寫入日志帆吻。

各參與者節(jié)點響應(yīng)協(xié)調(diào)者節(jié)點發(fā)起的詢問。如果參與者節(jié)點的事務(wù)操作實際執(zhí)行成功咙边,則它返回一個”同意”消息猜煮;如果參與者節(jié)點的事務(wù)操作實際執(zhí)行失敗次员,則它返回一個”中止”消息。 有時候王带,第一階段也被稱作投票階段淑蔚,即各參與者投票是否要繼續(xù)接下來的提交操作。愕撰。

階段2:提交階段(commit phase)

在該階段刹衫,協(xié)調(diào)者將基于第一個階段的投票結(jié)果進行決策:提交或取消。當(dāng)且僅當(dāng)所有的參與者同意提交事務(wù)協(xié)調(diào)者才通知所有的參與者提交事務(wù)搞挣,否則協(xié)調(diào)者將通知所有的參與者取消事務(wù)带迟。參與者在接收到協(xié)調(diào)者發(fā)來的消息后將執(zhí)行響應(yīng)的操作。

成功:

1)當(dāng)協(xié)調(diào)者節(jié)點從所有參與者節(jié)點獲得的相應(yīng)消息都為”同意”時:

2)協(xié)調(diào)者節(jié)點向所有參與者節(jié)點發(fā)出”正式提交”的請求囱桨。

3)參與者節(jié)點正式完成操作仓犬,并釋放在整個事務(wù)期間內(nèi)占用的資源。

4)參與者節(jié)點向協(xié)調(diào)者節(jié)點發(fā)送”完成”消息舍肠。

5)協(xié)調(diào)者節(jié)點收到所有參與者節(jié)點反饋的”完成”消息后搀继,完成事務(wù)掘猿。

失斒庵帷:

1)如果任一參與者節(jié)點在第一階段返回的響應(yīng)消息為”終止”,或者 協(xié)調(diào)者節(jié)點在第一階段的詢問超時之前無法獲取所有參與者節(jié)點的響應(yīng)消息時:

2)協(xié)調(diào)者節(jié)點向所有參與者節(jié)點發(fā)出”回滾操作”的請求弄唧。

3)參與者節(jié)點利用之前寫入的Undo信息執(zhí)行回滾啡专,并釋放在整個事務(wù)期間內(nèi)占用的資源险毁。

4)參與者節(jié)點向協(xié)調(diào)者節(jié)點發(fā)送”回滾完成”消息。

5)協(xié)調(diào)者節(jié)點收到所有參與者節(jié)點反饋的”回滾完成”消息后们童,取消事務(wù)畔况。

有時候,第二階段也被稱作完成階段慧库,因為無論結(jié)果怎樣跷跪,協(xié)調(diào)者都必須在此階段結(jié)束當(dāng)前事務(wù)。

2PC 存在的問題

1)同步阻塞問題

它的執(zhí)行過程中間齐板,節(jié)點都處于阻塞狀態(tài)吵瞻。即節(jié)點之間在等待對方的相應(yīng)消息時,它將什么也做不了甘磨。特別是橡羞,當(dāng)一個節(jié)點在已經(jīng)占有了某項資源的情況下,為了等待其他節(jié)點的響應(yīng)消息而陷入阻塞狀態(tài)時济舆,當(dāng)?shù)谌齻€節(jié)點嘗試訪問該節(jié)點占有的資源時卿泽,這個節(jié)點也將連帶陷入阻塞狀態(tài)

2)單點故障

由于協(xié)調(diào)者的重要性,一旦協(xié)調(diào)者發(fā)生故障滋觉。參與者會一直阻塞下去签夭。尤其在第二階段齐邦,協(xié)調(diào)者發(fā)生故障,那么所有的參與者還都處于鎖定事務(wù)資源的狀態(tài)中第租,而無法繼續(xù)完成事務(wù)操作措拇。(如果是協(xié)調(diào)者掛掉,可以重新選舉一個協(xié)調(diào)者慎宾,但是無法解決因為協(xié)調(diào)者宕機導(dǎo)致的參與者處于阻塞狀態(tài)的問題)

3)數(shù)據(jù)不一致

如果出現(xiàn)協(xié)調(diào)者和參與者都掛了的情況丐吓,有可能導(dǎo)致數(shù)據(jù)不一致。


3PC

三階段提交(Three-phase commit)璧诵,也叫三階段提交協(xié)議(Three-phase commit protocol)汰蜘,是二階段提交(2PC)的改進版本仇冯。

與兩階段提交不同的是之宿,三階段提交有兩個改動點。

? ? # 引入超時機制苛坚。同時在協(xié)調(diào)者和參與者中都引入超時機制比被。

? ? # 在第一階段和第二階段中插入一個準(zhǔn)備階段。保證了在最后提交階段之前各參與節(jié)點的狀態(tài)是一致的泼舱。

也就是說等缀,除了引入超時機制之外,3PC把2PC的準(zhǔn)備階段再次一分為二娇昙,這樣三階段提交就有CanCommit尺迂、PreCommit、DoCommit三個階段

CanCommit階段

3PC的CanCommit階段其實和2PC的準(zhǔn)備階段很像冒掌。協(xié)調(diào)者向參與者發(fā)送commit請求噪裕,參與者如果可以提交就返回Yes響應(yīng),否則返回No響應(yīng)股毫。

1.事務(wù)詢問協(xié)調(diào)者向參與者發(fā)送CanCommit請求膳音。詢問是否可以執(zhí)行事務(wù)提交操作。然后開始等待參與者的響應(yīng)铃诬。

2.響應(yīng)反饋參與者接到CanCommit請求之后祭陷,正常情況下,如果其自身認(rèn)為可以順利執(zhí)行事務(wù)趣席,則返回Yes響應(yīng)兵志,并進入預(yù)備狀態(tài)。否則反饋No

PreCommit階段

協(xié)調(diào)者根據(jù)參與者的反應(yīng)情況來決定是否可以記性事務(wù)的PreCommit操作宣肚。根據(jù)響應(yīng)情況想罕,有以下兩種可能。

假如協(xié)調(diào)者從所有的參與者獲得的反饋都是Yes響應(yīng)钉寝,那么就會執(zhí)行事務(wù)的預(yù)執(zhí)行弧呐。

1.發(fā)送預(yù)提交請求協(xié)調(diào)者向參與者發(fā)送PreCommit請求闸迷,并進入Prepared階段。

2.事務(wù)預(yù)提交參與者接收到PreCommit請求后俘枫,會執(zhí)行事務(wù)操作腥沽,并將undo和redo信息記錄到事務(wù)日志中。

3.響應(yīng)反饋如果參與者成功的執(zhí)行了事務(wù)操作鸠蚪,則返回ACK響應(yīng)今阳,同時開始等待最終指令。

假如有任何一個參與者向協(xié)調(diào)者發(fā)送了No響應(yīng)茅信,或者等待超時之后盾舌,協(xié)調(diào)者都沒有接到參與者的響應(yīng),那么就執(zhí)行事務(wù)的中斷蘸鲸。

1.發(fā)送中斷請求協(xié)調(diào)者向所有參與者發(fā)送abort請求妖谴。

2.中斷事務(wù)參與者收到來自協(xié)調(diào)者的abort請求之后(或超時之后,仍未收到協(xié)調(diào)者的請求)酌摇,執(zhí)行事務(wù)的中斷膝舅。

doCommit階段

該階段進行真正的事務(wù)提交,也可以分為以下兩種情況窑多。

執(zhí)行提交

1.發(fā)送提交請求協(xié)調(diào)接收到參與者發(fā)送的ACK響應(yīng)仍稀,那么他將從預(yù)提交狀態(tài)進入到提交狀態(tài)。并向所有參與者發(fā)送doCommit請求埂息。

2.事務(wù)提交參與者接收到doCommit請求之后技潘,執(zhí)行正式的事務(wù)提交。并在完成事務(wù)提交之后釋放所有事務(wù)資源千康。

3.響應(yīng)反饋事務(wù)提交完之后享幽,向協(xié)調(diào)者發(fā)送Ack響應(yīng)琉闪。

4.完成事務(wù)協(xié)調(diào)者接收到所有參與者的ack響應(yīng)之后,完成事務(wù)蛀蜜。

中斷事務(wù)協(xié)調(diào)者沒有接收到參與者發(fā)送的ACK響應(yīng)(可能是接受者發(fā)送的不是ACK響應(yīng),也可能響應(yīng)超時)霎奢,那么就會執(zhí)行中斷事務(wù)帝美。

1.發(fā)送中斷請求協(xié)調(diào)者向所有參與者發(fā)送abort請求

2.事務(wù)回滾參與者接收到abort請求之后,利用其在階段二記錄的undo信息來執(zhí)行事務(wù)的回滾操作舰褪,并在完成回滾之后釋放所有的事務(wù)資源疏橄。

3.反饋結(jié)果參與者完成事務(wù)回滾之后软族,向協(xié)調(diào)者發(fā)送ACK消息

4.中斷事務(wù)協(xié)調(diào)者接收到參與者反饋的ACK消息之后,執(zhí)行事務(wù)的中斷初茶。


2TCC Try-Confirm-Cancel)補償模式——最終一致性

有些場景下,我們根據(jù)自己的真實需要倔幼,并不需要純的2PC,比如你只關(guān)心數(shù)據(jù)的原子性與最終一致性,那2PC階段的阻塞是你不能忍受的组哩,那就有聰明的人想到了一種新的辦法蛛砰。就是我們今天要說的柔性事務(wù)TCC黍衙。「柔」主要是相對于「傳統(tǒng)」ACID的剛而言们豌,柔性事務(wù)只需要遵循BASE原則。而TCC是柔性事務(wù)的一種實現(xiàn)障癌。TCC是三個首字母,Try-Confirm-Cancel辩尊,具體描述是將整個操作分為上面這三步。兩個微服務(wù)間同時進行Try,在Try的階段會進行數(shù)據(jù)的校驗,檢查,資源的預(yù)創(chuàng)建智袭,如果都成功就會分別進行Confirm校哎,如果兩者都成功則整個TCC事務(wù)完成。如果Confirm時有一個服務(wù)有問題瞳步,則會轉(zhuǎn)向Cancel闷哆,相當(dāng)于進行Confirm的逆向操作。

TCC方案在電商谚攒、金融領(lǐng)域落地較多阳准。TCC方案其實是兩階段提交的一種改進。其將整個業(yè)務(wù)邏輯的每個分支顯式的分成了Try馏臭、Confirm野蝇、Cancel三個操作讼稚。Try部分完成業(yè)務(wù)的準(zhǔn)備工作,confirm部分完成業(yè)務(wù)的提交绕沈,cancel部分完成事務(wù)的回滾锐想。基本原理如下圖所示乍狐。

事務(wù)開始時赠摇,業(yè)務(wù)應(yīng)用會向事務(wù)協(xié)調(diào)器注冊啟動事務(wù)。之后業(yè)務(wù)應(yīng)用會調(diào)用所有服務(wù)的try接口浅蚪,完成一階段準(zhǔn)備藕帜。之后事務(wù)協(xié)調(diào)器會根據(jù)try接口返回情況,決定調(diào)用confirm接口或者cancel接口惜傲。如果接口調(diào)用失敗洽故,會進行重試。

其核心思想是:針對每個操作盗誊,都要注冊一個與其對應(yīng)的確認(rèn)和補償(撤銷)操作时甚。它分為三個階段:

? ? # Try階段主要是對業(yè)務(wù)系統(tǒng)做檢測及資源預(yù)留

? ? # Confirm階段主要是對業(yè)務(wù)系統(tǒng)做確認(rèn)提交,Try階段執(zhí)行成功并開始執(zhí)行 Confirm階段時哈踱,默認(rèn) Confirm階段是不會出錯的荒适。即:只要Try成功,Confirm一定成功开镣。

? ? # Cancel階段主要是在業(yè)務(wù)執(zhí)行錯誤刀诬,需要回滾的狀態(tài)下執(zhí)行的業(yè)務(wù)取消,預(yù)留資源釋放哑子。

基本實現(xiàn)原理

這些TCC的框架舅列,基本都是通過「注解」的形式,在注解中聲明Confirm方法與Cancel方法卧蜓,再通過AOP對帶點該注解的方法統(tǒng)一進行攔截,之后根據(jù)結(jié)果分別再執(zhí)行 Confirm 或者 Cancel把敞。

代碼類似這個樣子:

@Compensable(confirmMethod = "confirmRecord",cancelMethod = "cancelRecord", transactionContextEditor =MethodTransactionContextEditor.class)

public String record(TransactionContext transactionContext,CapitalTradeOrderDto tradeOrderDto) {

confirm方法

public void confirmRecord(TransactionContext transactionContext,CapitalTradeOrderDto tradeOrderDto) {

cancel方法:

public void cancelRecord(TransactionContext transactionContext,RedPacketTradeOrderDto tradeOrderDto) {

基于類似的框架弥奸,可以比較方便的滿足我們的業(yè)務(wù)使用場景。

TCC方案讓應(yīng)用自己定義數(shù)據(jù)庫操作的粒度奋早,使得降低鎖沖突盛霎、提高吞吐量成為可能。 當(dāng)然TCC方案也有不足之處耽装,集中表現(xiàn)在以下兩個方面:

? ? # 對應(yīng)用的侵入性強愤炸。業(yè)務(wù)邏輯的每個分支都需要實現(xiàn)try、confirm掉奄、cancel三個操作规个,應(yīng)用侵入性較強,改造成本高。

? ? # 實現(xiàn)難度較大诞仓。需要按照網(wǎng)絡(luò)狀態(tài)缤苫、系統(tǒng)故障等不同的失敗原因?qū)崿F(xiàn)不同的回滾策略。為了滿足一致性的要求墅拭,confirm和cancel接口必須實現(xiàn)冪等活玲。

上述原因?qū)е耇CC方案大多被研發(fā)實力較強、有迫切需求的大公司所采用谍婉。微服務(wù)倡導(dǎo)服務(wù)的輕量化舒憾、易部署,而TCC方案中很多事務(wù)的處理邏輯需要應(yīng)用自己編碼實現(xiàn)穗熬,復(fù)雜且開發(fā)量大珍剑。


3)基于消息的最終一致性

消息一致性方案是通過消息中間件保證上、下游應(yīng)用數(shù)據(jù)操作的一致性死陆≌凶荆基本思路是將本地操作和發(fā)送消息放在一個事務(wù)中,保證本地操作和消息發(fā)送要么兩者都成功或者都失敗措译。下游應(yīng)用向消息系統(tǒng)訂閱該消息别凤,收到消息后執(zhí)行相應(yīng)操作。

所謂的消息事務(wù)就是基于消息中間件的兩階段提交领虹,本質(zhì)上是對消息中間件的一種特殊利用规哪,它是將本地事務(wù)和發(fā)消息放在了一個分布式事務(wù)里,保證要么本地操作成功并且對外發(fā)消息成功塌衰,要么兩者都失敗诉稍,開源的RocketMQ就支持這一特性,具體原理如下:

1最疆、A系統(tǒng)向消息中間件發(fā)送一條預(yù)備消息

2杯巨、消息中間件保存預(yù)備消息并返回成功

3服爷、A執(zhí)行本地事務(wù)

4仍源、A發(fā)送提交消息給消息中間件

通過以上4步完成了一個消息事務(wù)。對于以上的4個步驟嚎于,每個步驟都可能產(chǎn)生錯誤镣屹,下面一一分析:

步驟一出錯女蜈,則整個事務(wù)失敗,不會執(zhí)行A的本地操作

步驟二出錯覆山,則整個事務(wù)失敗泥栖,不會執(zhí)行A的本地操作

步驟三出錯吧享,這時候需要回滾預(yù)備消息钢颂,怎么回滾殊鞭?答案是A系統(tǒng)實現(xiàn)一個消息中間件的回調(diào)接口锯仪,消息中間件會去不斷執(zhí)行回調(diào)接口,檢查A事務(wù)執(zhí)行是否執(zhí)行成功,如果失敗則回滾預(yù)備消息

步驟四出錯,這時候A的本地事務(wù)是成功的搓茬,那么消息中間件要回滾A嗎峻村?答案是不需要锡凝,其實通過回調(diào)接口粘昨,消息中間件能夠檢查到A執(zhí)行成功了窜锯,這時候其實不需要A發(fā)提交消息了,消息中間件可以自己對消息進行提交锚扎,從而完成整個消息事務(wù)

基于消息中間件的兩階段提交往往用在高并發(fā)場景下,將一個分布式事務(wù)拆成一個消息事務(wù)(A系統(tǒng)的本地操作+發(fā)消息)+ B系統(tǒng)的本地操作驾孔,其中B系統(tǒng)的操作由消息驅(qū)動,只要消息事務(wù)成功翠勉,那么A操作一定成功迹栓,消息也一定發(fā)出來了,這時候B會收到消息去執(zhí)行本地操作愿吹,如果本地操作失敗犁跪,消息會重投,直到B操作成功歹袁,這樣就變相地實現(xiàn)了A與B的分布式事務(wù)坷衍。原理如下:

? ? # 在系統(tǒng)A處理任務(wù)A前,首先向消息中間件發(fā)送一條消息

? ? # 消息中間件收到后將該條消息持久化条舔,但并不投遞枫耳。此時下游系統(tǒng)B仍然不知道該條消息的存在

? ? # 消息中間件持久化成功后,便向系統(tǒng)A返回一個確認(rèn)應(yīng)答

? ? # 系統(tǒng)A收到確認(rèn)應(yīng)答后孟抗,則可以開始處理任務(wù)A

? ? # 任務(wù)A處理完成后迁杨,向消息中間件發(fā)送Commit請求钻心。該請求發(fā)送完成后,對系統(tǒng)A而言铅协,該事務(wù)的處理過程就結(jié)束了捷沸,? ? ? ? ? ? 此時它可以處理別的任務(wù)了

? ? # 消息中間件收到Commit指令后,便向系統(tǒng)B投遞該消息狐史,從而觸發(fā)任務(wù)B的執(zhí)行

? ? # 當(dāng)任務(wù)B執(zhí)行完成后痒给,系統(tǒng)B向消息中間件返回一個確認(rèn)應(yīng)答,此時预皇,這個分布式事務(wù)完成

如果任務(wù)A處理失敗侈玄,那么需要進入回滾流程:

? ? # 若系統(tǒng)A在處理任務(wù)A時失敗,那么就會向消息中間件發(fā)送Rollback請求吟温。系統(tǒng)A發(fā)完之后便可以認(rèn)為回滾已經(jīng)完成序仙,它? ? ? ? ? 便可以去做其他的事情

? ? # 消息中間件收到回滾請求后,直接將該消息丟棄不投遞給系統(tǒng)B

新的問題

上面所介紹的Commit和Rollback都屬于理想情況鲁豪,但在實際系統(tǒng)中潘悼,Commit和Rollback指令都有可能在傳輸途中丟失。那么當(dāng)出現(xiàn)這種情況的時候爬橡,消息中間件是如何保證數(shù)據(jù)一致性呢治唤?——答案就是超時詢問機制。

系統(tǒng)A除了實現(xiàn)正常的業(yè)務(wù)流程外糙申,還需提供一個事務(wù)詢問的接口宾添,供消息中間件調(diào)用。當(dāng)消息中間件收到一條事務(wù)型消息后便開始計時柜裸,如果到了超時時間也沒收到系統(tǒng)A發(fā)來的Commit或Rollback指令的話缕陕,就會主動調(diào)用系統(tǒng)A提供的事務(wù)詢問接口詢問該系統(tǒng)目前的狀態(tài)。該接口會返回三種結(jié)果:

? ? # 提交:若獲得的狀態(tài)是“提交”疙挺,則將該消息投遞給系統(tǒng)B

? ? # 回滾:若獲得的狀態(tài)是“回滾”扛邑,則直接將條消息丟棄

? ? # 處理中:若獲得的狀態(tài)是“處理中”,則繼續(xù)等待

投遞過程的可靠性保證

我們知道當(dāng)上游系統(tǒng)A發(fā)出commit請求之后認(rèn)為事務(wù)已經(jīng)完成铐然,便可以處理其他的任務(wù)了蔬崩;那么消息中間件是怎么保證消息一定會被下游系統(tǒng)B成功消費呢?這是使用消息中間件投遞過程的可靠性來保證的

消息中間件向系統(tǒng)B投遞完消息后便進入阻塞等待狀態(tài)搀暑,如果消息在傳遞過程中丟失或者消息的確認(rèn)應(yīng)答在返回途中丟失沥阳,那么消息中間件在等待超時后會重新投遞直到消息被系統(tǒng)B成功消費為止

為什么是重新投遞而不是回滾?

這就涉及到整套分布式事務(wù)系統(tǒng)的實現(xiàn)成本問題自点。如果回滾的話沪袭,系統(tǒng)A就要提供回滾接口,這增加了開發(fā)成本樟氢,業(yè)務(wù)系統(tǒng)的復(fù)雜度也會隨之提高

異步與同步

上游系統(tǒng)A向消息中間件提交完消息后便可以去做別的事情冈绊。然而消息中間件將消息投遞給下游系統(tǒng)B后,它會阻塞等待直到下游系統(tǒng)返回B確認(rèn)應(yīng)答埠啃。為什么要這么設(shè)計呢?

首先,上游系統(tǒng)和消息中間件之間采用異步通信是為了提高系統(tǒng)并發(fā)度霎槐。業(yè)務(wù)系統(tǒng)直接和用戶打交道监右,用戶體驗尤為重要,因此這種異步通信方式能夠極大程度地降低用戶等待時間潦牛;

下游系統(tǒng)與消息中間件采用同步雖然降低系統(tǒng)并發(fā)度眶掌,但實現(xiàn)成本較低。在對并發(fā)度要求不是很高或者服務(wù)器資源較為充裕的情況下巴碗,我們可以選擇使用同步來降低系統(tǒng)的復(fù)雜度朴爬。

雖然上面的方案能夠完成A和B的操作,但是A和B并不是嚴(yán)格一致的橡淆,而是最終一致的召噩,我們在這里犧牲了一致性,換來了性能的大幅度提升逸爵。當(dāng)然具滴,這種玩法也是有風(fēng)險的,如果B一直執(zhí)行不成功师倔,那么一致性會被破壞构韵,具體要不要玩,還是得看業(yè)務(wù)能夠承擔(dān)多少風(fēng)險趋艘。

消息方案從本質(zhì)上講是將分布式事務(wù)轉(zhuǎn)換為兩個本地事務(wù)疲恢,然后依靠下游業(yè)務(wù)的重試機制達到最終一致性≈孪。基于消息的最終一致性方案對應(yīng)用侵入性也很高冈闭,應(yīng)用需要進行大量業(yè)務(wù)改造,成本較高抖单。


選擇建議

在面臨數(shù)據(jù)一致性問題的時候萎攒,首先要從業(yè)務(wù)需求的角度出發(fā),確定我們對于3 種一致性模型的接受程度矛绘,再通過具體場景來決定解決方案。

從應(yīng)用角度看羊精,分布式事務(wù)的現(xiàn)實場景常常無法規(guī)避喧锦,在有能力給出其他解決方案前束亏,2PC也是一個不錯的選擇。

對購物轉(zhuǎn)賬等電商和金融業(yè)務(wù)怕敬,中間件層的2PC最大問題在于業(yè)務(wù)不可見,一旦出現(xiàn)不可抗力或意想不到的一致性破壞越庇,如數(shù)據(jù)節(jié)點永久性宕機卤唉,業(yè)務(wù)難以根據(jù)2PC的日志進行補償桑驱。金融場景下熬的,數(shù)據(jù)一致性是命根押框,業(yè)務(wù)需要對數(shù)據(jù)有百分之百的掌控力,建議使用TCC這類分布式事務(wù)模型兑徘,或基于消息隊列的柔性事務(wù)框架,這兩種方案都在業(yè)務(wù)層實現(xiàn)肋联,業(yè)務(wù)開發(fā)者具有足夠掌控力,可以結(jié)合SOA框架來架構(gòu),包括Dubbo翘魄、Spring Cloud等舀奶。

侵入式方案的不足:

要求在應(yīng)用的業(yè)務(wù)層面把分布式事務(wù)技術(shù)約束考慮到設(shè)計中,通常每一個服務(wù)都需要設(shè)計實現(xiàn)正向和反向的冪等接口育勺。這樣的設(shè)計約束,往往會導(dǎo)致很高的研發(fā)和維護成本涧至。


4FESCAR方案Fast & EaSy Commit And Rollback阿里開源高效簡單易用的分布式事務(wù)解決方案

一個理想的分布式事務(wù)解決方案應(yīng)該:像使用本地事務(wù)一樣簡單南蓬,業(yè)務(wù)邏輯只關(guān)注業(yè)務(wù)層面的需求纺非,不需要考慮機制上的約束烧颖。我們要設(shè)計一個對業(yè)務(wù)無侵入的方案,所以從業(yè)務(wù)無侵入的XA方案來思考:是否可以在XA的基礎(chǔ)上演進,解決調(diào)XA方案面臨的問題呢优妙?

首先卡辰,如何定義分布式事務(wù)?

可以把一個分布式事務(wù)理解成一個包含了若干分支事務(wù)的全局事務(wù)。全局事務(wù)的職責(zé)是協(xié)調(diào)其下管轄的分支事務(wù)達成一致九妈,要么一起成功提交反砌,要么一起失敗回滾。此外萌朱,通常分支事務(wù)本身就是一個滿足ACID的本地事務(wù)宴树。這是我們對分布式事務(wù)結(jié)構(gòu)的解基本認(rèn)識,與XA是一致的晶疼。

其次酒贬,與XA的模型類似,F(xiàn)ESCAR有3個基本組件來協(xié)議分布式事務(wù)的處理過程:

? ? # 事務(wù)協(xié)調(diào)器(TC):維護全局事務(wù)的運行狀態(tài)翠霍,負(fù)責(zé)協(xié)調(diào)驅(qū)動全局事務(wù)的提交或回滾锭吨。

? ? # Transaction Manager(TM):定義全局事務(wù)的范圍:開始全局事務(wù),提交或回滾全局事務(wù)寒匙。

? ? # 資源管理器(RM):管理分支事務(wù)的資源零如,與TC通信以注冊分支事務(wù)和報告分支事務(wù)的狀態(tài),并驅(qū)動分支事務(wù)提交或? ? ? ? ?回滾锄弱。

一個典型的分布式事務(wù)過程:

(1)TM向TC申請開啟一個全局事務(wù)考蕾,全局事務(wù)創(chuàng)建成功并生成一個全局唯一的XID。

(2)XID在微服務(wù)調(diào)用鏈路的上下文中傳播会宪。

(3)RM向TC注冊分支事務(wù)肖卧,將其納入XID對應(yīng)全局事務(wù)的管轄。

(4)TM向TC發(fā)起針對XID的全局事務(wù)提交或回滾狈谊。

(5)TC調(diào)度XID下管轄的全部分支事務(wù)完成提交或回滾請求喜命。

至此,F(xiàn)escar的協(xié)議機制總體上看與XA是一致的河劝。

Fescar與XA的差別在哪里壁榕?

1、架構(gòu)層次

XA方案的RM實際上是在數(shù)據(jù)庫層赎瞎,RM本質(zhì)上就是數(shù)據(jù)庫自身(通過提供支持XA的驅(qū)動程序來供應(yīng)用使用)牌里。

而Fescar的RM是以二方包的形式作為中間件層部署在應(yīng)用程序這一側(cè)的,不依賴與數(shù)據(jù)庫本身對協(xié)議的支持务甥,當(dāng)然也不需要數(shù)據(jù)庫支持XA協(xié)議牡辽。這點對于微服務(wù)化的架構(gòu)來說是非常重要的:應(yīng)用層不需要為本地事務(wù)和分布式事務(wù)兩類不同場景來適配兩套不同的數(shù)據(jù)庫驅(qū)動。

這個設(shè)計剝離了分布式事務(wù)方案對數(shù)據(jù)庫在協(xié)議支持上的要求敞临。

2态辛、兩階段提交

先來看一下XA的2PC過程:

無論Phase2的決議是commit還是rollback,事務(wù)性資源的鎖都是要保持到Phase2完成才釋放挺尿。

設(shè)想一個正常運行的業(yè)務(wù)奏黑,大概率是90%以上的事務(wù)最終應(yīng)該是成功提交的炊邦,我們是否可以在Phase1就將本地事務(wù)提交呢?這樣90%以上的情況下熟史,可以省去Phase2持鎖的時間馁害,整體提高效率。

這個設(shè)計蹂匹,在絕大多數(shù)場景減少了事務(wù)持鎖的時間碘菜, 從而提高了事務(wù)的并發(fā)度。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末限寞,一起剝皮案震驚了整個濱河市忍啸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌昆烁,老刑警劉巖吊骤,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異静尼,居然都是意外死亡,警方通過查閱死者的電腦和手機传泊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門鼠渺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人眷细,你說我怎么就攤上這事拦盹。” “怎么了溪椎?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵普舆,是天一觀的道長。 經(jīng)常有香客問我校读,道長沼侣,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任歉秫,我火速辦了婚禮蛾洛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘雁芙。我一直安慰自己轧膘,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布兔甘。 她就那樣靜靜地躺著谎碍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪洞焙。 梳的紋絲不亂的頭發(fā)上蟆淀,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天拯啦,我揣著相機與錄音,去河邊找鬼扳碍。 笑死提岔,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的笋敞。 我是一名探鬼主播碱蒙,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼夯巷!你這毒婦竟也來了赛惩?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤趁餐,失蹤者是張志新(化名)和其女友劉穎喷兼,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體后雷,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡季惯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了臀突。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片勉抓。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖候学,靈堂內(nèi)的尸體忽然破棺而出藕筋,到底是詐尸還是另有隱情,我是刑警寧澤梳码,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布隐圾,位于F島的核電站,受9級特大地震影響掰茶,放射性物質(zhì)發(fā)生泄漏暇藏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一符匾、第九天 我趴在偏房一處隱蔽的房頂上張望叨咖。 院中可真熱鬧,春花似錦啊胶、人聲如沸甸各。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽趣倾。三九已至,卻和暖如春某饰,著一層夾襖步出監(jiān)牢的瞬間儒恋,已是汗流浹背善绎。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留诫尽,地道東北人禀酱。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像牧嫉,于是被迫代替她去往敵國和親剂跟。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容