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

服務(wù)層拆分

服務(wù)層拆分也就是業(yè)務(wù)的服務(wù)化,系統(tǒng)架構(gòu)的演進(jìn)是從集中式到分布式,業(yè)務(wù)功能之間越來越解耦合。

比如電商網(wǎng)站系統(tǒng),業(yè)務(wù)初期可能是一個單體工程支撐整套服務(wù),但隨著系統(tǒng)規(guī)模進(jìn)一步變大,參考康威定律,大多數(shù)公司都會將核心業(yè)務(wù)抽取出來,以作為獨(dú)立的服務(wù)。商品、訂單、庫存、賬號信息都提供了各自領(lǐng)域的服務(wù),業(yè)務(wù)邏輯的執(zhí)行散落在不同的服務(wù)器上。

用戶如果在某網(wǎng)站上進(jìn)行一個下單操作,那么會同時依賴訂單服務(wù)、庫存服務(wù)、支付扣款服務(wù),這幾個操作如果有一個失敗,那下單操作也就完不成,這就需要分布式事務(wù)來保證了。



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

分布式事務(wù)的解決方案,典型的有兩階段和三階段提交協(xié)議、 TCC 分段提交,和基于消息隊列的最終一致性設(shè)計。

2PC 兩階段提交

兩階段提交(2PC,Two-phase Commit Protocol)是非常經(jīng)典的強(qiáng)一致性、中心化的原子提交協(xié)議,在各種事務(wù)和一致性的解決方案中,都能看到兩階段提交的應(yīng)用。兩階段指的是commit-request階段和commit階段。


兩階段提交存在的問題:

1、資源被同步阻塞

在執(zhí)行過程中,所有參與節(jié)點(diǎn)都是事務(wù)獨(dú)占狀態(tài),當(dāng)參與者占有公共資源時,那么第三方節(jié)點(diǎn)訪問公共資源會被阻塞。

2、協(xié)調(diào)者可能出現(xiàn)單點(diǎn)故障

一旦協(xié)調(diào)者發(fā)生故障,參與者會一直阻塞下去。

3、在 Commit 階段出現(xiàn)數(shù)據(jù)不一致

在第二階段中,假設(shè)協(xié)調(diào)者發(fā)出了事務(wù) Commit 的通知,但是由于網(wǎng)絡(luò)問題該通知僅被一部分參與者所收到并執(zhí)行 Commit,其余的參與者沒有收到通知,一直處于阻塞狀態(tài),那么,這段時間就產(chǎn)生了數(shù)據(jù)的不一致性。


3PC 三階段提交

三階段提交協(xié)議(3PC,Three-phase_commit_protocol)是在 2PC 之上擴(kuò)展的提交協(xié)議,主要是為了解決兩階段提交協(xié)議的阻塞問題,從原來的兩個階段擴(kuò)展為三個階段,增加了超時機(jī)制。

三階段中的 Three Phase 分別為 CanCommit、PreCommit、DoCommit 階段。

三階段提交協(xié)議存在的問題

三階段提交協(xié)議同樣存在問題,具體表現(xiàn)為,在階段三中,如果參與者接收到了 PreCommit 消息后,出現(xiàn)了不能與協(xié)調(diào)者正常通信的問題,在這種情況下,參與者依然會進(jìn)行事務(wù)的提交,這就出現(xiàn)了數(shù)據(jù)的不一致性。


TCC 分段提交

TCC 是一個分布式事務(wù)的處理模型,將事務(wù)過程拆分為 Try、Confirm、Cancel 三個步驟,在保證強(qiáng)一致性的同時,最大限度提高系統(tǒng)的可伸縮性與可用性。

TCC 的具體流程如上圖所示:

Try 階段:調(diào)用 Try 接口,嘗試執(zhí)行業(yè)務(wù),完成所有業(yè)務(wù)檢查,預(yù)留業(yè)務(wù)資源。

Confirm 或 Cancel 階段:兩者是互斥的,只能進(jìn)入其中一個,并且都滿足冪等性,允許失敗重試。

Confirm 操作:對業(yè)務(wù)系統(tǒng)做確認(rèn)提交,確認(rèn)執(zhí)行業(yè)務(wù)操作,不做其他業(yè)務(wù)檢查,只使用 Try 階段預(yù)留的業(yè)務(wù)資源。

Cancel 操作:在業(yè)務(wù)執(zhí)行錯誤,需要回滾的狀態(tài)下執(zhí)行業(yè)務(wù)取消,釋放預(yù)留資源。

Try 階段失敗可以 Cancel,如果 Confirm 和 Cancel 階段失敗了怎么辦?

TCC 中會添加事務(wù)日志,如果 Confirm 或者 Cancel 階段出錯,則會進(jìn)行重試,所以這兩個階段需要支持冪等;如果重試失敗,則需要人工介入進(jìn)行恢復(fù)和處理等。


應(yīng)用 TCC 的優(yōu)缺點(diǎn)

實(shí)際開發(fā)中,TCC 的本質(zhì)是把數(shù)據(jù)庫的二階段提交上升到微服務(wù)來實(shí)現(xiàn),從而避免數(shù)據(jù)庫二階段中長事務(wù)引起的低性能風(fēng)險。

所以說,TCC 解決了跨服務(wù)的業(yè)務(wù)操作原子性問題,比如下訂單減庫存,多渠道組合支付等場景,通過 TCC 對業(yè)務(wù)進(jìn)行拆解,可以讓應(yīng)用自己定義數(shù)據(jù)庫操作的粒度,可以降低鎖沖突,提高系統(tǒng)的業(yè)務(wù)吞吐量。

TCC 的不足主要體現(xiàn)在對微服務(wù)的侵入性強(qiáng),TCC 需要對業(yè)務(wù)系統(tǒng)進(jìn)行改造,業(yè)務(wù)邏輯的每個分支都需要實(shí)現(xiàn) try、Confirm、Cancel 三個操作,并且 Confirm、Cancel 必須保證冪等。

另外 TCC 的事務(wù)管理器要記錄事務(wù)日志,也會損耗一定的性能。


從真實(shí)業(yè)務(wù)場景分析 TCC

下面以一個電商中的支付業(yè)務(wù)來演示,用戶在支付以后,需要進(jìn)行更新訂單狀態(tài)、扣減賬戶余額、增加賬戶積分和扣減商品操作。

在實(shí)際業(yè)務(wù)中為了防止超賣,有下單減庫存和付款減庫存的區(qū)別,支付除了賬戶余額,還有各種第三方支付等,這里我們?yōu)榱嗣枋龇奖?,統(tǒng)一使用扣款減庫存,扣款來源是用戶賬戶余額。

業(yè)務(wù)邏輯拆解

我們把訂單業(yè)務(wù)拆解為以下幾個步驟:

1、訂單更新為支付完成狀態(tài)

2、扣減用戶賬戶余額

3、增加用戶賬戶積分

4、扣減當(dāng)前商品的庫存

如果不使用事務(wù),上面的幾個步驟都可能出現(xiàn)失敗,最終會造成大量的數(shù)據(jù)不一致,比如訂單狀態(tài)更新失敗,扣款卻成功了;或者扣款失敗,庫存卻扣減了等情況,這個在業(yè)務(wù)上是不能接受的,會出現(xiàn)大量的客訴。

如果直接應(yīng)用事務(wù),不使用分布式事務(wù),比如在代碼中添加 Spring 的聲明式事務(wù) @Transactional 注解,這樣做實(shí)際上是在事務(wù)中嵌套了遠(yuǎn)程服務(wù)調(diào)用,一旦服務(wù)調(diào)用出現(xiàn)超時,事務(wù)無法提交,就會導(dǎo)致數(shù)據(jù)庫連接被占用,出現(xiàn)大量的阻塞和失敗,會導(dǎo)致服務(wù)宕機(jī)。另一方面,如果沒有定義額外的回滾操作,比如遇到異常,非 DB 的服務(wù)調(diào)用失敗時,則無法正確執(zhí)行回滾。


業(yè)務(wù)系統(tǒng)改造

下面應(yīng)用 TCC 事務(wù),需要對業(yè)務(wù)代碼改造,抽象 Try、Confirm 和 Cancel 階段。

Try 操作

Try 操作一般都是鎖定某個資源,設(shè)置一個預(yù)備的狀態(tài),凍結(jié)部分?jǐn)?shù)據(jù)。比如,訂單服務(wù)添加一個預(yù)備狀態(tài),修改為 UPDATING,也就是更新中的意思,凍結(jié)當(dāng)前訂單的操作,而不是直接修改為支付成功。

庫存服務(wù)設(shè)置凍結(jié)庫存,可以擴(kuò)展字段,也可以額外添加新的庫存凍結(jié)表。積分服務(wù)和庫存一樣,添加一個預(yù)增加積分,比如本次訂單積分是 100,添加一個額外的存儲表示等待增加的積分,賬戶余額服務(wù)等也是一樣的操作。

Confirm 操作

Confirm 操作就是把前邊的 Try 操作鎖定的資源提交,類比數(shù)據(jù)庫事務(wù)中的 Commit 操作。在支付的場景中,包括訂單狀態(tài)從準(zhǔn)備中更新為支付成功;庫存數(shù)據(jù)扣減凍結(jié)庫存,積分?jǐn)?shù)據(jù)增加預(yù)增加積分。

Cancel 操作

Cancel 操作執(zhí)行的是業(yè)務(wù)上的回滾處理,類比數(shù)據(jù)庫事務(wù)中的 Rollback 操作。首先訂單服務(wù),撤銷預(yù)備狀態(tài),還原為待支付狀態(tài)或者已取消狀態(tài),庫存服務(wù)刪除凍結(jié)庫存,添加到可銷售庫存中,積分服務(wù)也是一樣,將預(yù)增加積分扣減掉。


執(zhí)行業(yè)務(wù)操作

下面來分析業(yè)務(wù)的實(shí)際執(zhí)行操作,首先業(yè)務(wù)請求過來,開始執(zhí)行 Try 操作,如果 TCC 分布式事務(wù)框架感知到各個服務(wù)的 Try 階段都成功了以后,就會執(zhí)行各個服務(wù)的 Confirm 邏輯。

如果 Try 階段有操作不能正確執(zhí)行,比如訂單失效、庫存不足等,就會執(zhí)行 Cancel 的邏輯,取消事務(wù)提交。


TCC 分布式服務(wù)組件

在業(yè)務(wù)中引入 TCC 一般是依賴單獨(dú)的 TCC 事務(wù)框架,可以選擇自研或者應(yīng)用開源組件。TCC 框架扮演了資源管理器的角色,常用的 TCC 開源組件有 Tcc-transaction、ByteTCC、Spring-cloud-rest-tcc 等。

前面介紹過的 Seata,可以選擇 TCC 事務(wù)模式,也支持了 AT 模式及 Saga 模式。

以 Tcc-transaction 為例,源碼托管在 Github-tcc-transaction,提供了對 Spring 和 Dubbo 的適配,感興趣的話可以查看 tcc-transaction-tutorial-sample 學(xué)習(xí)。


基于消息補(bǔ)償?shù)淖罱K一致性

異步化在分布式系統(tǒng)設(shè)計中隨處可見,基于消息隊列的最終一致性就是一種異步事務(wù)機(jī)制,在業(yè)務(wù)中廣泛應(yīng)用。

在具體實(shí)現(xiàn)上,基于消息補(bǔ)償?shù)囊恢滦灾饕斜镜叵⒈砗偷谌娇煽肯㈥犃械取?/p>

下面介紹一下本地消息表,本地消息表的方案最初是由 ebay 的工程師提出,核心思想是將分布式事務(wù)拆分成本地事務(wù)進(jìn)行處理,通過消息日志的方式來異步執(zhí)行。

本地消息表是一種業(yè)務(wù)耦合的設(shè)計,消息生產(chǎn)方需要額外建一個事務(wù)消息表,并記錄消息發(fā)送狀態(tài),消息消費(fèi)方需要處理這個消息,并完成自己的業(yè)務(wù)邏輯,另外會有一個異步機(jī)制來定期掃描未完成的消息,確保最終一致性。

下面我們用下單減庫存業(yè)務(wù)來簡單模擬本地消息表的實(shí)現(xiàn)過程:

(1)系統(tǒng)收到下單請求,將訂單業(yè)務(wù)數(shù)據(jù)存入到訂單庫中,并且同時存儲該訂單對應(yīng)的消息數(shù)據(jù),比如購買商品的 ID 和數(shù)量,消息數(shù)據(jù)與訂單庫為同一庫,更新訂單和存儲消息為一個本地事務(wù),要么都成功,要么都失敗。

(2)庫存服務(wù)通過消息中間件收到庫存更新消息,調(diào)用庫存服務(wù)進(jìn)行業(yè)務(wù)操作,同時返回業(yè)務(wù)處理結(jié)果。

(3)消息生產(chǎn)方,也就是訂單服務(wù)收到處理結(jié)果后,將本地消息表的數(shù)據(jù)刪除或者設(shè)置為已完成。

(4)設(shè)置異步任務(wù),定時去掃描本地消息表,發(fā)現(xiàn)有未完成的任務(wù)則重試,保證最終一致性。

以上就是基于本地消息表一致性的主流程,在具體實(shí)踐中,還有許多分支情況,比如消息發(fā)送失敗、下游業(yè)務(wù)方處理失敗等,感興趣的同學(xué)可以思考下。


不要求最終一致性的柔性事務(wù)

除了上述幾種,還有一種不保證最終一致性的柔性事務(wù),也稱為盡最大努力通知,這種方式適合可以接受部分不一致的業(yè)務(wù)場景。

分布式事務(wù)有哪些開源組件

分布式事務(wù)開源組件應(yīng)用比較廣泛的是螞蟻金服開源的 Seata,也就是 Fescar,前身是阿里中間件團(tuán)隊發(fā)布的 TXC(Taobao Transaction Constructor)和升級后的 GTS(Global Transaction Service)。

Seata 的設(shè)計思想是把一個分布式事務(wù)拆分成一個包含了若干分支事務(wù)(Branch Transaction)的全局事務(wù)(Global Transaction)。分支事務(wù)本身就是一個滿足 ACID 的 本地事務(wù),全局事務(wù)的職責(zé)是協(xié)調(diào)其下管轄的分支事務(wù)達(dá)成一致,要么一起成功提交,要么一起失敗回滾。

在 Seata 中,全局事務(wù)對分支事務(wù)的協(xié)調(diào)基于兩階段提交協(xié)議,類似數(shù)據(jù)庫中的 XA 規(guī)范,XA 規(guī)范定義了三個組件來協(xié)調(diào)分布式事務(wù),分別是 AP 應(yīng)用程序、TM 事務(wù)管理器、RM 資源管理器、CRM 通信資源管理器。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容