9、架構(gòu)設(shè)計(jì)-分布式事務(wù)

一、產(chǎn)生背景

????????為了應(yīng)對互聯(lián)網(wǎng)環(huán)境帶來了海量的數(shù)據(jù)容量、連接數(shù)與訪問量,通過數(shù)據(jù)拆分實(shí)現(xiàn)數(shù)據(jù)庫能力的線性擴(kuò)展,通過微服務(wù)將復(fù)雜的單體應(yīng)用拆分為若干個功能簡單、松耦合的服務(wù)。系統(tǒng)微服務(wù)化后,一個看似簡單的功能,內(nèi)部可能需要調(diào)用多個服務(wù)并操作多個數(shù)據(jù)庫實(shí)現(xiàn),服務(wù)調(diào)用的分布式事務(wù)問題變的非常突出。分布式事務(wù)已經(jīng)成為微服務(wù)落地最大的阻礙,也是最具挑戰(zhàn)性的一個技術(shù)難題。 為此,本文將深入和大家探討微服務(wù)架構(gòu)下,分布式事務(wù)的各種解決方案。

二、理論基礎(chǔ)

1、ACID

????????事務(wù)(Transaction)是由一系列對系統(tǒng)中數(shù)據(jù)進(jìn)行訪問與更新的操作所組成的一個程序執(zhí)行邏輯單元(Unit),狹義上的事務(wù)特指數(shù)據(jù)庫事務(wù)。一方面,當(dāng)多個應(yīng)用程序并發(fā)訪問數(shù)據(jù)庫時,事務(wù)可以在這些應(yīng)用程序之間提供一個隔離方法,以防止彼此的操作互相干擾。另一方面,事務(wù)為數(shù)據(jù)庫操作序列提供了一個從失敗中恢復(fù)到正常狀態(tài)的方法,同時提供了數(shù)據(jù)庫即使在異常狀態(tài)下仍能保持?jǐn)?shù)據(jù)一致性的方法。事務(wù)具有四個特征,簡稱為事務(wù)的ACID特性。

????? 原子性(Atomicity):事務(wù)作為一個整體被執(zhí)行,包含在其中的對數(shù)據(jù)庫的操作要么全部被執(zhí)行,要么都不執(zhí)行。

????? 一致性(Consistency):事務(wù)應(yīng)確保數(shù)據(jù)庫的狀態(tài)從一個一致狀態(tài)轉(zhuǎn)變?yōu)榱硪粋€一致狀態(tài)。一致狀態(tài)的含義是數(shù)據(jù)庫中的數(shù)據(jù)應(yīng)滿足完整性約束。

????? 隔離性(Isolation):多個事務(wù)并發(fā)執(zhí)行時,一個事務(wù)的執(zhí)行不應(yīng)影響其他事務(wù)的執(zhí)行。

????? 持久性(Durability):已被提交的事務(wù)對數(shù)據(jù)庫的修改應(yīng)該永久保存在數(shù)據(jù)庫中。

2、CAP定理

CAP定理是由加州大學(xué)伯克利分校Eric Brewer教授提出來的,他指出WEB服務(wù)無法同時滿足一下3個屬性:

????????? 一致性(Consistency) : 客戶端知道一系列的操作都會同時發(fā)生(生效)

????????? 可用性(Availability) : 每個操作都必須以可預(yù)期的響應(yīng)結(jié)束

????????? 分區(qū)容錯性(Partition tolerance) : 即使出現(xiàn)單個組件無法可用,操作依然可以完成

????????具體地講在分布式系統(tǒng)中,在任何數(shù)據(jù)庫設(shè)計(jì)中,一個Web應(yīng)用至多只能同時支持上面的兩個屬性。顯然,任何橫向擴(kuò)展策略都要依賴于數(shù)據(jù)分區(qū)。因此,設(shè)計(jì)人員必須在一致性與可用性之間做出選擇。這個定理在迄今為止的分布式系統(tǒng)中都是適用的!

3、BASE理論

????????在分布式系統(tǒng)中,我們往往追求的是可用性,它的重要程序比一致性要高,那么如何實(shí)現(xiàn)高可用性呢? 前人已經(jīng)給我們提出來了另外一個理論,就是BASE理論,它是用來對CAP定理進(jìn)行進(jìn)一步擴(kuò)充的。BASE理論指的是:

????? Basically Available(基本可用)

????? Soft state(軟狀態(tài))

????? Eventually consistent(最終一致性)

????????BASE理論是對CAP中的一致性和可用性進(jìn)行一個權(quán)衡的結(jié)果,理論的核心思想就是:我們無法做到強(qiáng)一致,但每個應(yīng)用都可以根據(jù)自身的業(yè)務(wù)特點(diǎn),采用適當(dāng)?shù)姆绞絹硎瓜到y(tǒng)達(dá)到最終一致性(Eventual consistency)。

4、2PC

?????????兩階段提交,是實(shí)現(xiàn)分布式事務(wù)的成熟方案。第一階段是表決階段,是所有參與者都將本事務(wù)能否成功的反饋發(fā)給協(xié)調(diào)者;第二階段是執(zhí)行階段,協(xié)調(diào)者根據(jù)所有參與者的反饋,通知所有參與者,步調(diào)一致地在所有分支上提交,或者在所有分支上回滾。

????????兩階段提交可以滿足ACID,但代價是吞吐量。例如,數(shù)據(jù)庫需要頻繁地對資源上鎖等等。而且更致命的是,資源被鎖住的時間相對較長----在第一階段即需要上鎖,第二階段才能解鎖,依賴于所有分支的最慢者----這期間沒有任何人可以對該資源進(jìn)行修改。

????????兩階段提交理論的一個廣泛工業(yè)應(yīng)用是XA協(xié)議。目前幾乎所有收費(fèi)的商業(yè)數(shù)據(jù)庫都支持XA協(xié)議。XA協(xié)議已在業(yè)界成熟運(yùn)行數(shù)十年,但目前它在互聯(lián)網(wǎng)海量流量的應(yīng)用場景中,吞吐量這個瓶頸變得十分致命,因此很少被用到。

5、TCC

????????TCC(Try、Confirm、Cancel)是兩階段提交的一個變種。TCC提供了一個框架,需要應(yīng)用程序按照該框架編程,將業(yè)務(wù)邏輯的每個分支都分為Try、Confirm、Cancel三個操作集。TCC讓應(yīng)用程序自己定義數(shù)據(jù)庫操作的粒度,使得降低鎖沖突、提高吞吐量成為可能。以一個典型的訂單為例,按照TCC框架,應(yīng)用需要在Try階段將商品的庫存減去,將買家賬戶中的相應(yīng)金額扣掉,在臨時表中記錄下商品的數(shù)量,訂單的金額等信息;另外再編寫Confirm的邏輯,即在臨時表中刪除相關(guān)記錄,生成訂單,告知CRM、物流等系統(tǒng),等等;以及Cancel邏輯,即恢復(fù)庫存和買家賬戶金額,刪除臨時表相關(guān)記錄。

????????最終一致性是指事務(wù)進(jìn)行中,某些分支的中間狀態(tài)可以被事務(wù)外觀察到,即"讀未提交",從而導(dǎo)致多個分支的狀態(tài)可能不一致,但所有分支 最終 會達(dá)到要么全部提交,要么全部回滾的一致狀態(tài)。很明顯,最終一致性部分犧牲了ACID中的C和I,但它帶來了可觀的收益:資源不再需要長時間上鎖,極大地提高了吞吐量。最終一致性在互聯(lián)網(wǎng)應(yīng)用場景中被廣泛用做吞吐量和ACID的妥協(xié)點(diǎn)。

三、解決方案

1、兩階段提交(2PC)

????XA 是指由 X/Open 組織提出的分布式事務(wù)處理的規(guī)范。XA規(guī)范主要定義了Transaction Manager(TM)和Resource Manager(RM)之間的接口,結(jié)構(gòu)如下圖所示。

????????XA協(xié)議的流程可大致分為三個步驟:

????????步驟1:AP向TM創(chuàng)建全局事務(wù),TM向APP返回全局事務(wù)號。

????????步驟2:APP使用全局事務(wù)號,訪問RM的資源(當(dāng)RM為數(shù)據(jù)庫時,資源訪問就是SQL操作)。當(dāng)RM第一次收到訪問時,使用該全局事務(wù)號向TM注冊,TM返回事務(wù)分支事務(wù)號。

????????步驟3:AP向TM發(fā)出全局事務(wù)提交請求,TM與參與事務(wù)的RM通信,進(jìn)行提交處理,全部完成后,向AP返回結(jié)果。

????????TM與RM之間的提交處理,采用兩階段提交協(xié)議。TM在第一階段對所有的參與事務(wù)的RM請求“預(yù)備”操作,達(dá)成關(guān)于分布式事務(wù)一致性的共識。事務(wù)參與者必須完成所有的約束檢查,并且確保后續(xù)提交或放棄時所需要的數(shù)據(jù)已持久化。在第二階段,根據(jù)之前達(dá)到的提交或放棄的共識,請求所有參事務(wù)的RM完成相應(yīng)的操作。

????????提交事務(wù)的過程中需要在多個資源節(jié)點(diǎn)之間進(jìn)行協(xié)調(diào),而各節(jié)點(diǎn)對鎖資源的釋放必須等到事務(wù)最終提交時,所以兩階段提交在執(zhí)行同樣的事務(wù)時會比一階段提交消耗更多的時間。當(dāng)事務(wù)并發(fā)量達(dá)到一定數(shù)量時,就會出現(xiàn)大量事務(wù)積壓甚至出現(xiàn)死鎖,系統(tǒng)性能和處理吞吐量就會嚴(yán)重下滑。

2、補(bǔ)償事務(wù)(TCC)

????????TCC模式為全局事務(wù)執(zhí)行提供了一個框架,開發(fā)人員只需要實(shí)現(xiàn)每個事務(wù)分支的回滾,不需要記錄整個事務(wù)流程的操作日志。TCC 其實(shí)就是采用的補(bǔ)償機(jī)制,其核心思想是:針對每個操作,都要注冊一個與其對應(yīng)的確認(rèn)和補(bǔ)償(撤銷)操作。它分為三個階段:

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

????? Confirm 階段主要是對業(yè)務(wù)系統(tǒng)做確認(rèn)提交,Try階段執(zhí)行成功并開始執(zhí)行 Confirm階段時,默認(rèn) Confirm階段是不會出錯的。即:只要Try成功,Confirm一定成功。在這個階段真正執(zhí)行,不做業(yè)務(wù)檢查。

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

TCC模式結(jié)構(gòu)如下圖。

? ??說明:

????????? 一個完整的業(yè)務(wù)活動由一個主業(yè)務(wù)服務(wù)與若干從業(yè)務(wù)服務(wù)組成。

????????? 主業(yè)務(wù)服務(wù)負(fù)責(zé)發(fā)起并完成整個業(yè)務(wù)活動。

?????????? 從業(yè)務(wù)服務(wù)提供TCC型業(yè)務(wù)操作。

? ? ? ?? 業(yè)務(wù)活動管理器控制業(yè)務(wù)活動的一致性,它登記業(yè)務(wù)活動中的操作,并在業(yè)務(wù)活動提交時確認(rèn)所有的TCC型操作的confirm操作,在業(yè)務(wù)活動取消時調(diào)用所有TCC型操作的cancel操作。

????????TCC業(yè)務(wù)包括兩個階段完成:

????????? 第一階段:主業(yè)務(wù)服務(wù)分別調(diào)用所有從業(yè)務(wù)的 try 操作,并在活動管理器中登記所有從業(yè)務(wù)服務(wù)。當(dāng)所有從業(yè)務(wù)服務(wù)的 try 操作都調(diào)用成功或者某個從業(yè)務(wù)服務(wù)的 try 操作失敗,進(jìn)入第二階段。

????????? 第二階段:活動管理器根據(jù)第一階段的執(zhí)行結(jié)果來執(zhí)行 confirm 或 cancel 操作。

????????如果第一階段所有 try 操作都成功,則活動管理器調(diào)用所有從業(yè)務(wù)活動的 confirm操作。否則調(diào)用所有從業(yè)務(wù)服務(wù)的 cancel 操作。

????????使用TCC時要注意Try - Confirm - Cancel 3個操作的冪等控制,網(wǎng)絡(luò)原因,或者重試操作都有可能導(dǎo)致這幾個操作的重復(fù)執(zhí)行。

3、本地消息表(異步確保)

????????本地消息表這種實(shí)現(xiàn)方式應(yīng)該是業(yè)界使用最多的,其核心思想是將分布式事務(wù)拆分成本地事務(wù)進(jìn)行處理這種思路是來源于ebay。我們可以從下面的流程圖中看出其中的一些細(xì)節(jié):

????????基本思路就是:

????????消息生產(chǎn)方,需要額外建一個消息表,并記錄消息發(fā)送狀態(tài)。消息表和業(yè)務(wù)數(shù)據(jù)要在一個事務(wù)里提交,也就是說他們要在一個數(shù)據(jù)庫里面。然后消息會經(jīng)過MQ發(fā)送到消息的消費(fèi)方。如果消息發(fā)送失敗,會進(jìn)行重試發(fā)送。

????????消息消費(fèi)方,需要處理這個消息,并完成自己的業(yè)務(wù)邏輯。此時如果本地事務(wù)處理成功,表明已經(jīng)處理成功了,如果處理失敗,那么就會重試執(zhí)行。如果是業(yè)務(wù)上面的失敗,可以給生產(chǎn)方發(fā)送一個業(yè)務(wù)補(bǔ)償消息,通知生產(chǎn)方進(jìn)行回滾等操作。

????????生產(chǎn)方和消費(fèi)方定時掃描本地消息表,把還沒處理完成的消息或者失敗的消息再發(fā)送一遍。如果有靠譜的自動對賬補(bǔ)賬邏輯,這種方案還是非常實(shí)用的。

????????這種方案遵循BASE理論,采用的是最終一致性,筆者認(rèn)為是這幾種方案里面比較適合實(shí)際業(yè)務(wù)場景的,即不會出現(xiàn)像2PC那樣復(fù)雜的實(shí)現(xiàn)(當(dāng)調(diào)用鏈很長的時候,2PC的可用性是非常低的),也不會像TCC那樣可能出現(xiàn)確認(rèn)或者回滾不了的情況。

4、MQ事務(wù)消息

????????有一些第三方的MQ是支持事務(wù)消息的,比如RocketMQ,他們支持事務(wù)消息的方式也是類似于采用的二階段提交,但是市面上一些主流的MQ都是不支持事務(wù)消息的,比如 RabbitMQ 和 Kafka 都不支持。

????????以阿里的 RocketMQ 中間件為例,其思路大致為:

????????第一階段Prepared消息,會拿到消息的地址。第二階段執(zhí)行本地事務(wù),第三階段通過第一階段拿到的地址去訪問消息,并修改狀態(tài)。

????????也就是說在業(yè)務(wù)方法內(nèi)要想消息隊(duì)列提交兩次請求,一次發(fā)送消息和一次確認(rèn)消息。如果確認(rèn)消息發(fā)送失敗了RocketMQ會定期掃描消息集群中的事務(wù)消息,這時候發(fā)現(xiàn)了Prepared消息,它會向消息發(fā)送者確認(rèn),所以生產(chǎn)方需要實(shí)現(xiàn)一個check接口,RocketMQ會根據(jù)發(fā)送端設(shè)置的策略來決定是回滾還是繼續(xù)發(fā)送確認(rèn)消息。這樣就保證了消息發(fā)送與本地事務(wù)同時成功或同時失敗。

????MQ事務(wù)消息的一種可能實(shí)現(xiàn)的結(jié)構(gòu)如下圖。

????說明:

????????1)業(yè)務(wù)處理服務(wù)在業(yè)務(wù)事務(wù)提交前,向?qū)崟r消息服務(wù)請求發(fā)送消息,實(shí)時消息服務(wù)只記錄消息數(shù)據(jù),而不真正發(fā)送。

????????2)業(yè)務(wù)處理服務(wù)在業(yè)務(wù)事務(wù)提交后,向?qū)崟r消息服務(wù)確認(rèn)發(fā)送。只有在得到確認(rèn)發(fā)送指令后,實(shí)時消息服務(wù)才真正發(fā)送消息。

????????3)業(yè)務(wù)處理服務(wù)在業(yè)務(wù)事務(wù)回滾后,向?qū)崟r消息服務(wù)取消發(fā)送。

????????4)消息狀態(tài)確認(rèn)系統(tǒng)定期找到未確認(rèn)發(fā)送或回滾發(fā)送的消息,向業(yè)務(wù)處理服務(wù)詢問消息狀態(tài),業(yè)務(wù)處理服務(wù)根據(jù)消息ID或消息內(nèi)容確定該消息是否有效。

????????通過消息進(jìn)行事務(wù)異步的方式,可以保證業(yè)務(wù)數(shù)據(jù)操作和消息的發(fā)送同時執(zhí)行成功或失敗,保持了事務(wù)的最終一致性。

????????采用可靠消息的方式,在兩個事務(wù)間實(shí)現(xiàn)分布式事務(wù)時,可以很好地滿足事務(wù)最終一致性以及事務(wù)的回滾,但如果一個事務(wù)上下文中超過兩個事務(wù)操作后,需要開發(fā)人員實(shí)現(xiàn)整個事務(wù)流程的操作日志的記錄、每個事務(wù)分支的回滾以及整個流程的準(zhǔn)確調(diào)度。

5、SAGA事務(wù)模型

? ??????Saga事務(wù)模型又叫做長時間運(yùn)行的事務(wù)(Long-running-transaction), 它是由普林斯頓大學(xué)的H.Garcia-Molina等人提出,它描述的是另外一種在沒有兩階段提交的的情況下解決分布式系統(tǒng)中復(fù)雜的業(yè)務(wù)事務(wù)問題。

????????我們這里說的是一種基于 Sagas 機(jī)制的工作流事務(wù)模型。該模型其核心思想就是拆分分布式系統(tǒng)中的長事務(wù)為多個短事務(wù),或者叫多個本地事務(wù),然后由 Sagas 工作流引擎負(fù)責(zé)協(xié)調(diào),如果整個流程正常結(jié)束,那么就算是業(yè)務(wù)成功完成,如果在這過程中實(shí)現(xiàn)失敗,那么Sagas工作流引擎就會以相反的順序調(diào)用補(bǔ)償操作,重新進(jìn)行業(yè)務(wù)回滾。

四、開源軟件Seata

1、簡介

????????2007 開始,螞蟻金服自主研發(fā)分布式事務(wù)分布式事務(wù)中間件 XTS(eXtended Transaction Service),在內(nèi)部廣泛應(yīng)用并解決金融核心場景下的跨數(shù)據(jù)庫、跨服務(wù)數(shù)據(jù)一致性問題,最終以 DTX(Distributed Transaction eXtended)的云產(chǎn)品化展現(xiàn)并對外開放。與此同時,阿里巴巴中間件團(tuán)隊(duì)發(fā)布 TXC(Taobao Transaction Constructor),為集團(tuán)內(nèi)應(yīng)用提供分布式事務(wù)服務(wù),經(jīng)過多年的技術(shù)沉淀,于 2016 年產(chǎn)品化改造為 GTS(Global Transaction Service),通過阿里云解決方案在眾多外部客戶中落地實(shí)施。

????????2019 年 1 月,基于技術(shù)積累,阿里巴巴中間件團(tuán)隊(duì)發(fā)起了開源項(xiàng)目 Fescar(Fast & EaSy Commit And Rollback, Fescar),和社區(qū)一起共建分布式事務(wù)解決方案。Fescar 為解決微服務(wù)架構(gòu)下的分布式事務(wù)問題交出了一份與眾不同的答卷。而 Fescar 的愿景是讓分布式事務(wù)的使用像本地事務(wù)的使用一樣簡單和高效。最終的目標(biāo)是希望可以讓 Fescar 適用于所有的分布式事務(wù)場景。

????????為了達(dá)到適用于更多的分布式事務(wù)業(yè)務(wù)場景的目標(biāo),螞蟻金服加入 Fescar 社區(qū)共建,在 Fescar 0.4.0 版本中加入了 TCC 模式。螞蟻金服的加入引發(fā)了社區(qū)核心成員的討論,為了達(dá)到適用于所有的分布式事務(wù)業(yè)務(wù)場景的目標(biāo),也為了社區(qū)更中立、更開放、生態(tài)更加豐富,社區(qū)核心成員們決定進(jìn)行品牌升級,改名 Seata。Seata 意為:Simple Extensible Autonomous Transaction Architecture,是一套一站式分布式事務(wù)解決方案。

2、架構(gòu)

下圖描述了GTS一種可能的實(shí)現(xiàn)架構(gòu)。

????????與XA架構(gòu)相同,GTS架構(gòu)由應(yīng)用、事務(wù)管理器、資源管理器三個部分組成。資源管理器由事務(wù)分支處理模塊、鏡像查詢構(gòu)造模塊、并發(fā)控制模塊、恢復(fù)控制模塊,以及存儲在數(shù)據(jù)庫中的GTS事務(wù)信息(GTS鎖表與GTS日志表)等組成。

?????事務(wù)分支處理模塊:是資源管理器的外部接口,并完成內(nèi)部各模塊的調(diào)用。

? ? ?鏡像查詢構(gòu)造模塊:從Insert、Update、Delete語句,生成該操作對應(yīng)記錄集的鏡像查詢語句。例如table_name表包含兩個字段column1和column2,column1為主鍵,則鏡像查詢語句為select column1, column2 from table_name where column1=v1。

?????并發(fā)控制模塊:基于GTS事務(wù)鎖表,維護(hù)讀寫并發(fā)控制。

?????恢復(fù)控制模塊:基于GTS日志表,進(jìn)行故障恢復(fù)。

3、內(nèi)部運(yùn)行機(jī)制

AT(Automatic Transaction)模式

????????Seata AT模式是基于XA事務(wù)演進(jìn)而來的一個分布式事務(wù)中間件,XA是一個基于數(shù)據(jù)庫實(shí)現(xiàn)的分布式事務(wù)協(xié)議,本質(zhì)上和兩階段提交一樣,需要數(shù)據(jù)庫支持,Mysql5.6以上版本支持XA協(xié)議,其他數(shù)據(jù)庫如Oracle,DB2也實(shí)現(xiàn)了XA接口。核心思路是把一個分布式事務(wù)理解成一個包含了若干分支事務(wù)的全局事務(wù)。全局事務(wù)的職責(zé)是協(xié)調(diào)其下管轄的分支事務(wù)達(dá)成一致,要么一起成功提交,要么一起失敗回滾。定義 3 個組件來協(xié)議分布式事務(wù)的處理過程。

Transaction Coordinator (TC):?事務(wù)協(xié)調(diào)器,維護(hù)全局事務(wù)的運(yùn)行狀態(tài),負(fù)責(zé)協(xié)調(diào)并驅(qū)動全局事務(wù)的提交或回滾。

Transaction Manager (TM):?控制全局事務(wù)的邊界,負(fù)責(zé)開啟一個全局事務(wù),并最終發(fā)起全局提交或全局回滾的決議。

Resource Manager (RM):?控制分支事務(wù),負(fù)責(zé)分支注冊、狀態(tài)匯報(bào),并接收事務(wù)協(xié)調(diào)器的指令,驅(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 的全局提交或回滾決議。

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

1)第一階段

????????Seata 的 JDBC 數(shù)據(jù)源代理通過對業(yè)務(wù) SQL 的解析,把業(yè)務(wù)數(shù)據(jù)在更新前后的數(shù)據(jù)鏡像組織成回滾日志,利用 本地事務(wù) 的 ACID 特性,將業(yè)務(wù)數(shù)據(jù)的更新和回滾日志的寫入在同一個 本地事務(wù) 中提交。這樣,可以保證:任何提交的業(yè)務(wù)數(shù)據(jù)的更新一定有相應(yīng)的回滾日志存在。

????????基于這樣的機(jī)制,分支的本地事務(wù)便可以在全局事務(wù)的第一階段提交,并馬上釋放本地事務(wù)鎖定的資源。這也是Seata和XA事務(wù)的不同之處,兩階段提交往往對資源的鎖定需要持續(xù)到第二階段實(shí)際的提交或者回滾操作,而有了回滾日志之后,可以在第一階段釋放對資源的鎖定,降低了鎖范圍,提高效率,即使第二階段發(fā)生異常需要回滾,只需找對undolog中對應(yīng)數(shù)據(jù)并反解析成sql來達(dá)到回滾目的。同時Seata通過代理數(shù)據(jù)源將業(yè)務(wù)sql的執(zhí)行解析成undolog來與業(yè)務(wù)數(shù)據(jù)的更新同時入庫,達(dá)到了對業(yè)務(wù)無侵入的效果。

2)第二階段

????如果決議是全局提交,此時分支事務(wù)此時已經(jīng)完成提交,不需要同步協(xié)調(diào)處理(只需要異步清理回滾日志),Phase2 可以非??焖俚赝瓿?。

????????如果決議是全局回滾,RM 收到協(xié)調(diào)器發(fā)來的回滾請求,通過 XID 和 Branch ID 找到相應(yīng)的回滾日志記錄,通過回滾記錄生成反向的更新 SQL 并執(zhí)行,以完成分支的回滾。

???????AT模型中有一個?重要前提:分支事務(wù)中涉及的資源,必須?是支持ACID事務(wù)的關(guān)系型數(shù)據(jù)庫。分支的提交和回滾機(jī)制,都依賴于本地事務(wù)的保障。所以,如果應(yīng)用使用的數(shù)據(jù)庫是不支持事務(wù)的,或根本不是關(guān)系型數(shù)據(jù)庫,就不適用。另外,目前 Seata 的實(shí)現(xiàn)還存在一些局限,比如:事務(wù)隔離級別最高支持到?讀已提交?的水平,SQL 的解析還不能涵蓋全部的語法等。為了覆蓋 Fescar 原生機(jī)制暫時不能支持應(yīng)用場景,我們定義了另外一種工作模式。

?MT(Manual Transaction)模式

這種模式下,分支事務(wù)需要應(yīng)用自己來定義業(yè)務(wù)本身及提交和回滾的邏輯。MT 模式一方面是 AT 模式的補(bǔ)充。另外,更重要的價值在于,通過 MT 模式可以把眾多非事務(wù)性資源納入全局事務(wù)的管理中。AT 和 MT 模式的分支從根本上行為模式是一致的,所以可以完全兼容,即,一個全局事務(wù)中,可以同時存在 AT 和 MT 的分支。這樣就可以達(dá)到全面覆蓋業(yè)務(wù)場景的目的:AT 模式可以支持的,使用 AT 模式;AT 模式暫時支持不了的,用 MT 模式來替代。另外,自然的,MT 模式管理的非事務(wù)性資源也可以和支持事務(wù)的關(guān)系型數(shù)據(jù)庫資源一起,納入同一個分布式事務(wù)的管理中。

4、具體處理流程

分別描述了insert/delete/update操作、讀已提交操作、提交操作和回滾操作等四個操作的序列圖(一種可能的實(shí)現(xiàn)方式)。

1)insert/delete/update操作流程序列圖

2)讀已提交操作流程序列圖

3)提交操作流程序列圖

4)回滾操作流程序列圖

五、開源軟件ServiceComb Pack

1、簡介

????????ServiceComb是華為云于2017年6月開源的微服務(wù)框架,并于2017年12月正式進(jìn)入Apache軟件基金會孵化。其包括一站式的服務(wù)注冊、服務(wù)治理、動態(tài)配置功能,具備服務(wù)化契約增強(qiáng)、多語言SDK支持、多通信協(xié)議支持等優(yōu)勢特性, 并提供SAGA數(shù)據(jù)最終一致性方案解決微服務(wù)架構(gòu)數(shù)據(jù)一致性難題。ServiceComb 兼容Spring Cloud等業(yè)界流行微服務(wù)框架,互通業(yè)界生態(tài)。

????????ServiceComb Saga是針對微服務(wù)分布式事務(wù)最終一致性問題提供的解決方案。Saga分布式事務(wù)是由多個相關(guān)聯(lián)的的本地事務(wù)操作所組成。Saga協(xié)調(diào)器負(fù)責(zé)保證Saga事務(wù)的最終一致性。當(dāng)本地事務(wù)執(zhí)行出錯時,Saga協(xié)調(diào)器會自動執(zhí)行相關(guān)的恢復(fù)操作保證分布式事務(wù)的最終一致性。相比其它的分布式事務(wù)一致性方案,Saga在簡化事務(wù)配置以及提供多種事務(wù)恢復(fù)機(jī)制上有很明顯的優(yōu)勢。目前開發(fā)的ServiceComb Saga 0.1.0支持用戶通過Annoation的方式定義事務(wù)操作以及撤銷事務(wù)操作的服務(wù)接口, 同時Saga協(xié)調(diào)器監(jiān)控追蹤事務(wù)的執(zhí)行情況并負(fù)責(zé)協(xié)調(diào)事務(wù)執(zhí)行者,保證事務(wù)的最終一致性。

2、架構(gòu)

????????Pack中包含兩個組件,即?alpha?和?omega。

????????alpha充當(dāng)協(xié)調(diào)者的角色,主要負(fù)責(zé)對事務(wù)的事件進(jìn)行持久化存儲以及協(xié)調(diào)子事務(wù)的狀態(tài),使其得以最終與全局事務(wù)的狀態(tài)保持一致。????????

????????omega是微服務(wù)中內(nèi)嵌的一個agent,負(fù)責(zé)對網(wǎng)絡(luò)請求進(jìn)行攔截并向alpha上報(bào)事務(wù)事件,并在異常情況下根據(jù)alpha下發(fā)的指令執(zhí)行相應(yīng)的補(bǔ)償操作。

3、Omega內(nèi)部運(yùn)行機(jī)制

????????omega是微服務(wù)中內(nèi)嵌的一個agent。當(dāng)服務(wù)收到請求時,omega會將其攔截并從中提取請求信息中的全局事務(wù)id作為其自身的全局事務(wù)id(即Saga事件id),并提取本地事務(wù)id作為其父事務(wù)id。在預(yù)處理階段,alpha會記錄事務(wù)開始的事件;在后處理階段,alpha會記錄事務(wù)結(jié)束的事件。因此,每個成功的子事務(wù)都有一一對應(yīng)的開始及結(jié)束事件。

4、服務(wù)間通信流程

????????服務(wù)間通信的流程與Zipkin的類似。在服務(wù)生產(chǎn)方,omega會攔截請求中事務(wù)相關(guān)的id來提取事務(wù)的上下文。在服務(wù)消費(fèi)方,omega會在請求中注入事務(wù)相關(guān)的id來傳遞事務(wù)的上下文。通過服務(wù)提供方和服務(wù)消費(fèi)方的這種協(xié)作處理,子事務(wù)能連接起來形成一個完整的全局事務(wù)。

5、Saga具體處理流程

????????Saga處理場景是要求相關(guān)的子事務(wù)提供事務(wù)處理函數(shù)同時也提供補(bǔ)償函數(shù)。Saga協(xié)調(diào)器alpha會根據(jù)事務(wù)的執(zhí)行情況向omega發(fā)送相關(guān)的指令,確定是否向前重試或者向后恢復(fù)。

1)成功場景

成功場景下,每個事務(wù)都會有開始和有對應(yīng)的結(jié)束事件。

2)異常場景

????????異常場景下,omega會向alpha上報(bào)中斷事件,然后alpha會向該全局事務(wù)的其它已完成的子事務(wù)發(fā)送補(bǔ)償指令,確保最終所有的子事務(wù)要么都成功,要么都回滾。

3)超時場景 (需要調(diào)整)

????????超時場景下,已超時的事件會被alpha的定期掃描器檢測出來,與此同時,該超時事務(wù)對應(yīng)的全局事務(wù)也會被中斷。

6、TCC具體處理流程

????????TCC(try-confirm-cancel)與Saga事務(wù)處理方式相比多了一個Try方法。事務(wù)調(diào)用的發(fā)起方來根據(jù)事務(wù)的執(zhí)行情況協(xié)調(diào)相關(guān)各方進(jìn)行提交事務(wù)或者回滾事務(wù)。

1)成功場景

成功場景下, 每個事務(wù)都會有開始和對應(yīng)的結(jié)束事件。

2)異常場景

????????異常場景下,事務(wù)發(fā)起方會向alpha上報(bào)異常事件,然后alpha會向該全局事務(wù)的其它已完成的子事務(wù)發(fā)送補(bǔ)償指令,確保最終所有的子事務(wù)要么都成功,要么都回滾。

六、Seata和ServiceComb Pack對比

1、出身

????????Seata是阿里巴巴開源的分布式事務(wù)中間件,基于其內(nèi)部的TXC和GTS的技術(shù)積累。雖然此框架非常活躍,但是19年剛剛開源,用于生產(chǎn)環(huán)境風(fēng)險(xiǎn)較大。

????????servicecomb-pack出自華為微服務(wù)框架servicecomb,servicecomb在Apache已經(jīng)畢業(yè)了,但是一直比較“低調(diào)”。知名數(shù)據(jù)庫中間Sharding-Sphere采用的就是servicecomb-pack提供的saga方案。

2、實(shí)現(xiàn)原理

????????Seata實(shí)際上本質(zhì)就是將一個分布式事務(wù)轉(zhuǎn)化為多個單庫事務(wù)。采用Saga的思想,所有的正向操作,都保留逆向操作。一旦要回滾,只需要執(zhí)行逆向操作就可以了。在業(yè)務(wù)數(shù)據(jù)庫中額外增加一張事件表,這個事件表就是關(guān)鍵所在,在更新正常業(yè)務(wù)數(shù)據(jù)庫的同時,在一個單庫事務(wù)內(nèi)(同一個數(shù)據(jù)庫連接)同步更新事件表,這樣來保證不丟數(shù)據(jù)。我們可以回顧一下一致性的要求,“要么同時成功,要么同時失敗。”單庫事務(wù)就可以保證。

? ??????servicecomb-pack和Seata一樣,同樣是saga的思想,所有的正向操作,都保留逆向操作。一旦要回滾,只需要執(zhí)行逆向操作就可以了。但是,除此之外,servicecomb-pack也支持TCC。如圖所示,Omega作為一個客戶端,攔截所有的事務(wù)操作,事務(wù)開始向Alpha記錄開始記錄,事務(wù)結(jié)束向Alpha記錄事務(wù)結(jié)束記錄,一旦出現(xiàn)問題,直接在Alpha事件表中生成逆向操作,你應(yīng)該已經(jīng)看出來了,和fescar不同的是,事件表中的數(shù)據(jù)存儲在全局協(xié)調(diào)者(alpha)這一側(cè)。

????????兩種做法各有優(yōu)劣吧,存在業(yè)務(wù)側(cè)實(shí)際上是有侵入的,不是絕對意義上的無侵入,雖然單庫事務(wù)性能不錯,但是事件表的所有操作都會影響正常業(yè)務(wù),無法做到更好的隔離性。存在協(xié)調(diào)者一側(cè)相對來說隔離性更好一些,但是這里會有概率產(chǎn)生不一致,例如,實(shí)際上業(yè)務(wù)操作已經(jīng)完成了,數(shù)據(jù)庫更新成功了,但是寫事件日志可能會失敗,這時候協(xié)調(diào)者會認(rèn)為業(yè)務(wù)操作也失敗了。

3、其它對比

穩(wěn)定性:servicecomb-pack略勝一籌。更早的項(xiàng)目。

隔離性:Seata寫隔離通過TC提供的分布式鎖來實(shí)現(xiàn),讀隔離通過select for update實(shí)現(xiàn),當(dāng)然,servicecomb-pack同樣可以通過select for update實(shí)現(xiàn)讀隔離。

復(fù)雜度:servicecomb-pack略勝一籌。角色少,思路簡單。業(yè)務(wù)側(cè),兩個框架都可以通過簡單的注解實(shí)現(xiàn)。

文檔:fescar略勝一籌。

性能:沒有實(shí)際測試,從原理上來講,相差無幾。

支持的數(shù)據(jù)庫:fescar目前只支持mysql,servicecomb-pack的方案不區(qū)分?jǐn)?shù)據(jù)庫。

4、總結(jié)

????????雖然兩個框架的目標(biāo)都是讓業(yè)務(wù)開發(fā)人員更簡單,不用關(guān)心分布式事務(wù)的問題,但是在我看來,如果要使用,還是要搞清楚原理,除非對此問題非常敏感,否則,應(yīng)該謹(jǐn)慎使用,能不用最好不用。 兩個框架都在快速發(fā)展中,從實(shí)現(xiàn)思想上來講非常相似,都是很好的解決方案,未來的情況主要看投入程度。

最后編輯于
?著作權(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)容