国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【高級(jí)篇】分布式事務(wù)

這篇具有很好參考價(jià)值的文章主要介紹了【高級(jí)篇】分布式事務(wù)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

分布式事務(wù)

1.分布式事務(wù)問題

1.1.本地事務(wù)

本地事務(wù),也就是傳統(tǒng)的單機(jī)事務(wù)。在傳統(tǒng)數(shù)據(jù)庫(kù)事務(wù)中,必須要滿足四個(gè)原則:

【高級(jí)篇】分布式事務(wù)

1.2.分布式事務(wù)

分布式事務(wù),就是指不是在單個(gè)服務(wù)或單個(gè)數(shù)據(jù)庫(kù)架構(gòu)下,產(chǎn)生的事務(wù),例如:

  • 跨數(shù)據(jù)源的分布式事務(wù)
  • 跨服務(wù)的分布式事務(wù)
  • 綜合情況

在數(shù)據(jù)庫(kù)水平拆分、服務(wù)垂直拆分之后,一個(gè)業(yè)務(wù)操作通常要跨多個(gè)數(shù)據(jù)庫(kù)、服務(wù)才能完成。例如電商行業(yè)中比較常見的下單付款案例,包括下面幾個(gè)行為:

  • 創(chuàng)建新訂單
  • 扣減商品庫(kù)存
  • 從用戶賬戶余額扣除金額

完成上面的操作需要訪問三個(gè)不同的微服務(wù)和三個(gè)不同的數(shù)據(jù)庫(kù)。

【高級(jí)篇】分布式事務(wù)

訂單的創(chuàng)建、庫(kù)存的扣減、賬戶扣款在每一個(gè)服務(wù)和數(shù)據(jù)庫(kù)內(nèi)是一個(gè)本地事務(wù),可以保證ACID原則。

但是當(dāng)我們把三件事情看做一個(gè)"業(yè)務(wù)",要滿足保證“業(yè)務(wù)”的原子性,要么所有操作全部成功,要么全部失敗,不允許出現(xiàn)部分成功部分失敗的現(xiàn)象,這就是分布式系統(tǒng)下的事務(wù)了。

此時(shí)ACID難以滿足,這是分布式事務(wù)要解決的問題

1.3.演示分布式事務(wù)問題

我們通過一個(gè)案例來演示分布式事務(wù)的問題:

1)創(chuàng)建數(shù)據(jù)庫(kù),名為seata_demo,然后導(dǎo)入課前資料提供的SQL文件:

【高級(jí)篇】分布式事務(wù)

2)導(dǎo)入課前資料提供的微服務(wù):

【高級(jí)篇】分布式事務(wù)

微服務(wù)結(jié)構(gòu)如下:
【高級(jí)篇】分布式事務(wù)

其中:

seata-demo:父工程,負(fù)責(zé)管理項(xiàng)目依賴

  • account-service:賬戶服務(wù),負(fù)責(zé)管理用戶的資金賬戶。提供扣減余額的接口
  • storage-service:庫(kù)存服務(wù),負(fù)責(zé)管理商品庫(kù)存。提供扣減庫(kù)存的接口
  • order-service:訂單服務(wù),負(fù)責(zé)管理訂單。創(chuàng)建訂單時(shí),需要調(diào)用account-service和storage-service

3)啟動(dòng)nacos、所有微服務(wù)

4)測(cè)試下單功能,發(fā)出Post請(qǐng)求:

請(qǐng)求如下:

curl --location --request POST 'http://localhost:8082/order?userId=user202103032042012&commodityCode=100202003032041&count=20&money=200'

如圖:

【高級(jí)篇】分布式事務(wù)

測(cè)試發(fā)現(xiàn),當(dāng)庫(kù)存不足時(shí),如果余額已經(jīng)扣減,并不會(huì)回滾,出現(xiàn)了分布式事務(wù)問題。

2.理論基礎(chǔ)

解決分布式事務(wù)問題,需要一些分布式系統(tǒng)的基礎(chǔ)知識(shí)作為理論指導(dǎo)。

2.1.CAP定理

1998年,加州大學(xué)的計(jì)算機(jī)科學(xué)家 Eric Brewer 提出,分布式系統(tǒng)有三個(gè)指標(biāo)。

  • Consistency(一致性)
  • Availability(可用性)
  • Partition tolerance (分區(qū)容錯(cuò)性)

【高級(jí)篇】分布式事務(wù)

它們的第一個(gè)字母分別是 C、A、P。

Eric Brewer 說,這三個(gè)指標(biāo)不可能同時(shí)做到。這個(gè)結(jié)論就叫做 CAP 定理。

2.1.1.一致性

Consistency(一致性):用戶訪問分布式系統(tǒng)中的任意節(jié)點(diǎn),得到的數(shù)據(jù)必須一致。

比如現(xiàn)在包含兩個(gè)節(jié)點(diǎn),其中的初始數(shù)據(jù)是一致的:

【高級(jí)篇】分布式事務(wù)

當(dāng)我們修改其中一個(gè)節(jié)點(diǎn)的數(shù)據(jù)時(shí),兩者的數(shù)據(jù)產(chǎn)生了差異:

【高級(jí)篇】分布式事務(wù)

要想保住一致性,就必須實(shí)現(xiàn)node01 到 node02的數(shù)據(jù) 同步:

【高級(jí)篇】分布式事務(wù)

2.1.2.可用性

Availability (可用性):用戶訪問集群中的任意健康節(jié)點(diǎn),必須能得到響應(yīng),而不是超時(shí)或拒絕。

如圖,有三個(gè)節(jié)點(diǎn)的集群,訪問任何一個(gè)都可以及時(shí)得到響應(yīng):

【高級(jí)篇】分布式事務(wù)

當(dāng)有部分節(jié)點(diǎn)因?yàn)榫W(wǎng)絡(luò)故障或其它原因無法訪問時(shí),代表節(jié)點(diǎn)不可用:
【高級(jí)篇】分布式事務(wù)

2.1.3.分區(qū)容錯(cuò)

Partition(分區(qū)):因?yàn)榫W(wǎng)絡(luò)故障或其它原因?qū)е路植际较到y(tǒng)中的部分節(jié)點(diǎn)與其它節(jié)點(diǎn)失去連接,形成獨(dú)立分區(qū)。

【高級(jí)篇】分布式事務(wù)

Tolerance(容錯(cuò)):在集群出現(xiàn)分區(qū)時(shí),整個(gè)系統(tǒng)也要持續(xù)對(duì)外提供服務(wù)

2.1.4.矛盾

在分布式系統(tǒng)中,系統(tǒng)間的網(wǎng)絡(luò)不能100%保證健康,一定會(huì)有故障的時(shí)候,而服務(wù)有必須對(duì)外保證服務(wù)。因此Partition Tolerance不可避免。

當(dāng)節(jié)點(diǎn)接收到新的數(shù)據(jù)變更時(shí),就會(huì)出現(xiàn)問題了:
【高級(jí)篇】分布式事務(wù)

如果此時(shí)要保證一致性,就必須等待網(wǎng)絡(luò)恢復(fù),完成數(shù)據(jù)同步后,整個(gè)集群才對(duì)外提供服務(wù),服務(wù)處于阻塞狀態(tài),不可用。

如果此時(shí)要保證可用性,就不能等待網(wǎng)絡(luò)恢復(fù),那node01、node02與node03之間就會(huì)出現(xiàn)數(shù)據(jù)不一致。

也就是說,在P一定會(huì)出現(xiàn)的情況下,A和C之間只能實(shí)現(xiàn)一個(gè)。

2.2.BASE理論

BASE理論是對(duì)CAP的一種解決思路,包含三個(gè)思想:

  • Basically Available (基本可用):分布式系統(tǒng)在出現(xiàn)故障時(shí),允許損失部分可用性,即保證核心可用。
  • **Soft State(軟狀態(tài)):**在一定時(shí)間內(nèi),允許出現(xiàn)中間狀態(tài),比如臨時(shí)的不一致狀態(tài)。
  • Eventually Consistent(最終一致性):雖然無法保證強(qiáng)一致性,但是在軟狀態(tài)結(jié)束后,最終達(dá)到數(shù)據(jù)一致。

2.3.解決分布式事務(wù)的思路

分布式事務(wù)最大的問題是各個(gè)子事務(wù)的一致性問題,因此可以借鑒CAP定理和BASE理論,有兩種解決思路:

  • AP模式:各子事務(wù)分別執(zhí)行和提交,允許出現(xiàn)結(jié)果不一致,然后采用彌補(bǔ)措施恢復(fù)數(shù)據(jù)即可,實(shí)現(xiàn)最終一致。

  • CP模式:各個(gè)子事務(wù)執(zhí)行后互相等待,同時(shí)提交,同時(shí)回滾,達(dá)成強(qiáng)一致。但事務(wù)等待過程中,處于弱可用狀態(tài)。

但不管是哪一種模式,都需要在子系統(tǒng)事務(wù)之間互相通訊,協(xié)調(diào)事務(wù)狀態(tài),也就是需要一個(gè)事務(wù)協(xié)調(diào)者(TC)

【高級(jí)篇】分布式事務(wù)

這里的子系統(tǒng)事務(wù),稱為分支事務(wù);有關(guān)聯(lián)的各個(gè)分支事務(wù)在一起稱為全局事務(wù)。

3.初識(shí)Seata

Seata是 2019 年 1 月份螞蟻金服和阿里巴巴共同開源的分布式事務(wù)解決方案。致力于提供高性能和簡(jiǎn)單易用的分布式事務(wù)服務(wù),為用戶打造一站式的分布式解決方案。

官網(wǎng)地址:http://seata.io/,其中的文檔、播客中提供了大量的使用說明、源碼分析。

【高級(jí)篇】分布式事務(wù)

3.1.Seata的架構(gòu)

Seata事務(wù)管理中有三個(gè)重要的角色:

  • TC (Transaction Coordinator) - **事務(wù)協(xié)調(diào)者:**維護(hù)全局和分支事務(wù)的狀態(tài),協(xié)調(diào)全局事務(wù)提交或回滾。

  • TM (Transaction Manager) - **事務(wù)管理器:**定義全局事務(wù)的范圍、開始全局事務(wù)、提交或回滾全局事務(wù)。

  • RM (Resource Manager) - **資源管理器:**管理分支事務(wù)處理的資源,與TC交談以注冊(cè)分支事務(wù)和報(bào)告分支事務(wù)的狀態(tài),并驅(qū)動(dòng)分支事務(wù)提交或回滾。

整體的架構(gòu)如圖:

【高級(jí)篇】分布式事務(wù)

Seata基于上述架構(gòu)提供了四種不同的分布式事務(wù)解決方案:

  • XA模式:強(qiáng)一致性分階段事務(wù)模式,犧牲了一定的可用性,無業(yè)務(wù)侵入
  • TCC模式:最終一致的分階段事務(wù)模式,有業(yè)務(wù)侵入
  • AT模式:最終一致的分階段事務(wù)模式,無業(yè)務(wù)侵入,也是Seata的默認(rèn)模式
  • SAGA模式:長(zhǎng)事務(wù)模式,有業(yè)務(wù)侵入

無論哪種方案,都離不開TC,也就是事務(wù)的協(xié)調(diào)者。

3.2.部署TC服務(wù)

參考 seata的部署和集成

3.3.微服務(wù)集成Seata

我們以order-service為例來演示。

3.3.1.引入依賴

首先,在order-service中引入依賴:

<!--seata-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
    <exclusions>
        <!--版本較低,1.3.0,因此排除--> 
        <exclusion>
            <artifactId>seata-spring-boot-starter</artifactId>
            <groupId>io.seata</groupId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>io.seata</groupId>
    <artifactId>seata-spring-boot-starter</artifactId>
    <!--seata starter 采用1.4.2版本-->
    <version>${seata.version}</version>
</dependency>

3.3.2.配置TC地址

在order-service中的application.yml中,配置TC服務(wù)信息,通過注冊(cè)中心nacos,結(jié)合服務(wù)名稱獲取TC地址:

seata:
  registry: # TC服務(wù)注冊(cè)中心的配置,微服務(wù)根據(jù)這些信息去注冊(cè)中心獲取tc服務(wù)地址
    type: nacos # 注冊(cè)中心類型 nacos
    nacos:
      server-addr: 127.0.0.1:8848 # nacos地址
      namespace: "" # namespace,默認(rèn)為空
      group: DEFAULT_GROUP # 分組,默認(rèn)是DEFAULT_GROUP
      application: seata-tc-server # seata服務(wù)名稱
      username: nacos
      password: nacos
  tx-service-group: seata-demo # 事務(wù)組名稱
  service:
    vgroup-mapping: # 事務(wù)組與cluster的映射關(guān)系
      seata-demo: SH

微服務(wù)如何根據(jù)這些配置尋找TC的地址呢?

我們知道注冊(cè)到Nacos中的微服務(wù),確定一個(gè)具體實(shí)例需要四個(gè)信息:

  • namespace:命名空間
  • group:分組
  • application:服務(wù)名
  • cluster:集群名

以上四個(gè)信息,在剛才的yaml文件中都能找到:

【高級(jí)篇】分布式事務(wù)

namespace為空,就是默認(rèn)的public

結(jié)合起來,TC服務(wù)的信息就是:public@DEFAULT_GROUP@seata-tc-server@SH,這樣就能確定TC服務(wù)集群了。然后就可以去Nacos拉取對(duì)應(yīng)的實(shí)例信息了。

3.3.3.其它服務(wù)

其它兩個(gè)微服務(wù)也都參考o(jì)rder-service的步驟來做,完全一樣。

4.動(dòng)手實(shí)踐

下面我們就一起學(xué)習(xí)下Seata中的四種不同的事務(wù)模式。

4.1.XA模式

XA 規(guī)范 是 X/Open 組織定義的分布式事務(wù)處理(DTP,Distributed Transaction Processing)標(biāo)準(zhǔn),XA 規(guī)范 描述了全局的TM與局部的RM之間的接口,幾乎所有主流的數(shù)據(jù)庫(kù)都對(duì) XA 規(guī)范 提供了支持。

4.1.1.兩階段提交

XA是規(guī)范,目前主流數(shù)據(jù)庫(kù)都實(shí)現(xiàn)了這種規(guī)范,實(shí)現(xiàn)的原理都是基于兩階段提交。

正常情況:

【高級(jí)篇】分布式事務(wù)

異常情況:

【高級(jí)篇】分布式事務(wù)

一階段:

  • 事務(wù)協(xié)調(diào)者通知每個(gè)事物參與者執(zhí)行本地事務(wù)
  • 本地事務(wù)執(zhí)行完成后報(bào)告事務(wù)執(zhí)行狀態(tài)給事務(wù)協(xié)調(diào)者,此時(shí)事務(wù)不提交,繼續(xù)持有數(shù)據(jù)庫(kù)鎖

二階段:

  • 事務(wù)協(xié)調(diào)者基于一階段的報(bào)告來判斷下一步操作
    • 如果一階段都成功,則通知所有事務(wù)參與者,提交事務(wù)
    • 如果一階段任意一個(gè)參與者失敗,則通知所有事務(wù)參與者回滾事務(wù)

4.1.2.Seata的XA模型

Seata對(duì)原始的XA模式做了簡(jiǎn)單的封裝和改造,以適應(yīng)自己的事務(wù)模型,基本架構(gòu)如圖:

【高級(jí)篇】分布式事務(wù)

RM一階段的工作:

? ① 注冊(cè)分支事務(wù)到TC

? ② 執(zhí)行分支業(yè)務(wù)sql但不提交

? ③ 報(bào)告執(zhí)行狀態(tài)到TC

TC二階段的工作:

  • TC檢測(cè)各分支事務(wù)執(zhí)行狀態(tài)

    a.如果都成功,通知所有RM提交事務(wù)

    b.如果有失敗,通知所有RM回滾事務(wù)

RM二階段的工作:

  • 接收TC指令,提交或回滾事務(wù)

4.1.3.優(yōu)缺點(diǎn)

XA模式的優(yōu)點(diǎn)是什么?

  • 事務(wù)的強(qiáng)一致性,滿足ACID原則。
  • 常用數(shù)據(jù)庫(kù)都支持,實(shí)現(xiàn)簡(jiǎn)單,并且沒有代碼侵入

XA模式的缺點(diǎn)是什么?

  • 因?yàn)橐浑A段需要鎖定數(shù)據(jù)庫(kù)資源,等待二階段結(jié)束才釋放,性能較差
  • 依賴關(guān)系型數(shù)據(jù)庫(kù)實(shí)現(xiàn)事務(wù)

4.1.4.實(shí)現(xiàn)XA模式

Seata的starter已經(jīng)完成了XA模式的自動(dòng)裝配,實(shí)現(xiàn)非常簡(jiǎn)單,步驟如下:

1)修改application.yml文件(每個(gè)參與事務(wù)的微服務(wù)),開啟XA模式:

seata:
  data-source-proxy-mode: XA

2)給發(fā)起全局事務(wù)的入口方法添加@GlobalTransactional注解:

本例中是OrderServiceImpl中的create方法.
【高級(jí)篇】分布式事務(wù)

3)重啟服務(wù)并測(cè)試

重啟order-service,再次測(cè)試,發(fā)現(xiàn)無論怎樣,三個(gè)微服務(wù)都能成功回滾。

4.2.AT模式

AT模式同樣是分階段提交的事務(wù)模型,不過缺彌補(bǔ)了XA模型中資源鎖定周期過長(zhǎng)的缺陷。

4.2.1.Seata的AT模型

基本流程圖:
【高級(jí)篇】分布式事務(wù)

階段一RM的工作:

  • 注冊(cè)分支事務(wù)
  • 記錄undo-log(數(shù)據(jù)快照)
  • 執(zhí)行業(yè)務(wù)sql并提交
  • 報(bào)告事務(wù)狀態(tài)

階段二提交時(shí)RM的工作:

  • 刪除undo-log即可

階段二回滾時(shí)RM的工作:

  • 根據(jù)undo-log恢復(fù)數(shù)據(jù)到更新前

4.2.2.流程梳理

我們用一個(gè)真實(shí)的業(yè)務(wù)來梳理下AT模式的原理。

比如,現(xiàn)在又一個(gè)數(shù)據(jù)庫(kù)表,記錄用戶余額:

id money
1 100

其中一個(gè)分支業(yè)務(wù)要執(zhí)行的SQL為:

update tb_account set money = money - 10 where id = 1

AT模式下,當(dāng)前分支事務(wù)執(zhí)行流程如下:

一階段:

1)TM發(fā)起并注冊(cè)全局事務(wù)到TC

2)TM調(diào)用分支事務(wù)

3)分支事務(wù)準(zhǔn)備執(zhí)行業(yè)務(wù)SQL

4)RM攔截業(yè)務(wù)SQL,根據(jù)where條件查詢?cè)紨?shù)據(jù),形成快照。

{
    "id": 1, "money": 100
}

5)RM執(zhí)行業(yè)務(wù)SQL,提交本地事務(wù),釋放數(shù)據(jù)庫(kù)鎖。此時(shí) money = 90

6)RM報(bào)告本地事務(wù)狀態(tài)給TC

二階段:

1)TM通知TC事務(wù)結(jié)束

2)TC檢查分支事務(wù)狀態(tài)

? a)如果都成功,則立即刪除快照

? b)如果有分支事務(wù)失敗,需要回滾。讀取快照數(shù)據(jù)({"id": 1, "money": 100}),將快照恢復(fù)到數(shù)據(jù)庫(kù)。此時(shí)數(shù)據(jù)庫(kù)再次恢復(fù)為100

流程圖:
【高級(jí)篇】分布式事務(wù)

4.2.3.AT與XA的區(qū)別

簡(jiǎn)述AT模式與XA模式最大的區(qū)別是什么?

  • XA模式一階段不提交事務(wù),鎖定資源;AT模式一階段直接提交,不鎖定資源。
  • XA模式依賴數(shù)據(jù)庫(kù)機(jī)制實(shí)現(xiàn)回滾;AT模式利用數(shù)據(jù)快照實(shí)現(xiàn)數(shù)據(jù)回滾。
  • XA模式強(qiáng)一致;AT模式最終一致

4.2.4.臟寫問題

在多線程并發(fā)訪問AT模式的分布式事務(wù)時(shí),有可能出現(xiàn)臟寫問題,如圖:

【高級(jí)篇】分布式事務(wù)

解決思路就是引入了全局鎖的概念。在釋放DB鎖之前,先拿到全局鎖。避免同一時(shí)刻有另外一個(gè)事務(wù)來操作當(dāng)前數(shù)據(jù)。

【高級(jí)篇】分布式事務(wù)

4.2.5.優(yōu)缺點(diǎn)

AT模式的優(yōu)點(diǎn):

  • 一階段完成直接提交事務(wù),釋放數(shù)據(jù)庫(kù)資源,性能比較好
  • 利用全局鎖實(shí)現(xiàn)讀寫隔離
  • 沒有代碼侵入,框架自動(dòng)完成回滾和提交

AT模式的缺點(diǎn):

  • 兩階段之間屬于軟狀態(tài),屬于最終一致
  • 框架的快照功能會(huì)影響性能,但比XA模式要好很多

4.2.6.實(shí)現(xiàn)AT模式

AT模式中的快照生成、回滾等動(dòng)作都是由框架自動(dòng)完成,沒有任何代碼侵入,因此實(shí)現(xiàn)非常簡(jiǎn)單。

只不過,AT模式需要一個(gè)表來記錄全局鎖、另一張表來記錄數(shù)據(jù)快照undo_log。

1)導(dǎo)入數(shù)據(jù)庫(kù)表,記錄全局鎖

導(dǎo)入課前資料提供的Sql文件:seata-at.sql,其中l(wèi)ock_table導(dǎo)入到TC服務(wù)關(guān)聯(lián)的數(shù)據(jù)庫(kù),undo_log表導(dǎo)入到微服務(wù)關(guān)聯(lián)的數(shù)據(jù)庫(kù):
【高級(jí)篇】分布式事務(wù)

2)修改application.yml文件,將事務(wù)模式修改為AT模式即可:

seata:
  data-source-proxy-mode: AT # 默認(rèn)就是AT

3)重啟服務(wù)并測(cè)試

4.3.TCC模式

TCC模式與AT模式非常相似,每階段都是獨(dú)立事務(wù),不同的是TCC通過人工編碼來實(shí)現(xiàn)數(shù)據(jù)恢復(fù)。需要實(shí)現(xiàn)三個(gè)方法:

  • Try:資源的檢測(cè)和預(yù)留;

  • Confirm:完成資源操作業(yè)務(wù);要求 Try 成功 Confirm 一定要能成功。

  • Cancel:預(yù)留資源釋放,可以理解為try的反向操作。

4.3.1.流程分析

舉例,一個(gè)扣減用戶余額的業(yè)務(wù)。假設(shè)賬戶A原來余額是100,需要余額扣減30元。

  • 階段一( Try ):檢查余額是否充足,如果充足則凍結(jié)金額增加30元,可用余額扣除30

初始余額:

【高級(jí)篇】分布式事務(wù)

余額充足,可以凍結(jié):

【高級(jí)篇】分布式事務(wù)

此時(shí),總金額 = 凍結(jié)金額 + 可用金額,數(shù)量依然是100不變。事務(wù)直接提交無需等待其它事務(wù)。

  • 階段二(Confirm):假如要提交(Confirm),則凍結(jié)金額扣減30

確認(rèn)可以提交,不過之前可用金額已經(jīng)扣減過了,這里只要清除凍結(jié)金額就好了:

【高級(jí)篇】分布式事務(wù)

此時(shí),總金額 = 凍結(jié)金額 + 可用金額 = 0 + 70 = 70元

  • 階段二(Canncel):如果要回滾(Cancel),則凍結(jié)金額扣減30,可用余額增加30

需要回滾,那么就要釋放凍結(jié)金額,恢復(fù)可用金額:

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-9Fup2a0S-1686045878545)(assets/image-20210724182810734.png)]

4.3.2.Seata的TCC模型

Seata中的TCC模型依然延續(xù)之前的事務(wù)架構(gòu),如圖:
【高級(jí)篇】分布式事務(wù)

4.3.3.優(yōu)缺點(diǎn)

TCC模式的每個(gè)階段是做什么的?

  • Try:資源檢查和預(yù)留
  • Confirm:業(yè)務(wù)執(zhí)行和提交
  • Cancel:預(yù)留資源的釋放

TCC的優(yōu)點(diǎn)是什么?

  • 一階段完成直接提交事務(wù),釋放數(shù)據(jù)庫(kù)資源,性能好
  • 相比AT模型,無需生成快照,無需使用全局鎖,性能最強(qiáng)
  • 不依賴數(shù)據(jù)庫(kù)事務(wù),而是依賴補(bǔ)償操作,可以用于非事務(wù)型數(shù)據(jù)庫(kù)

TCC的缺點(diǎn)是什么?

  • 有代碼侵入,需要人為編寫try、Confirm和Cancel接口,太麻煩
  • 軟狀態(tài),事務(wù)是最終一致
  • 需要考慮Confirm和Cancel的失敗情況,做好冪等處理

4.3.4.事務(wù)懸掛和空回滾

1)空回滾

當(dāng)某分支事務(wù)的try階段阻塞時(shí),可能導(dǎo)致全局事務(wù)超時(shí)而觸發(fā)二階段的cancel操作。在未執(zhí)行try操作時(shí)先執(zhí)行了cancel操作,這時(shí)cancel不能做回滾,就是空回滾。

如圖:

【高級(jí)篇】分布式事務(wù)

執(zhí)行cancel操作時(shí),應(yīng)當(dāng)判斷try是否已經(jīng)執(zhí)行,如果尚未執(zhí)行,則應(yīng)該空回滾。

2)業(yè)務(wù)懸掛

對(duì)于已經(jīng)空回滾的業(yè)務(wù),之前被阻塞的try操作恢復(fù),繼續(xù)執(zhí)行try,就永遠(yuǎn)不可能confirm或cancel ,事務(wù)一直處于中間狀態(tài),這就是業(yè)務(wù)懸掛。

執(zhí)行try操作時(shí),應(yīng)當(dāng)判斷cancel是否已經(jīng)執(zhí)行過了,如果已經(jīng)執(zhí)行,應(yīng)當(dāng)阻止空回滾后的try操作,避免懸掛

4.3.5.實(shí)現(xiàn)TCC模式

解決空回滾和業(yè)務(wù)懸掛問題,必須要記錄當(dāng)前事務(wù)狀態(tài),是在try、還是cancel?

1)思路分析

這里我們定義一張表:

CREATE TABLE `account_freeze_tbl` (
  `xid` varchar(128) NOT NULL,
  `user_id` varchar(255) DEFAULT NULL COMMENT '用戶id',
  `freeze_money` int(11) unsigned DEFAULT '0' COMMENT '凍結(jié)金額',
  `state` int(1) DEFAULT NULL COMMENT '事務(wù)狀態(tài),0:try,1:confirm,2:cancel',
  PRIMARY KEY (`xid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

其中:

  • xid:是全局事務(wù)id
  • freeze_money:用來記錄用戶凍結(jié)金額
  • state:用來記錄事務(wù)狀態(tài)

那此時(shí),我們的業(yè)務(wù)開怎么做呢?

  • Try業(yè)務(wù):
    • 記錄凍結(jié)金額和事務(wù)狀態(tài)到account_freeze表
    • 扣減account表可用金額
  • Confirm業(yè)務(wù)
    • 根據(jù)xid刪除account_freeze表的凍結(jié)記錄
  • Cancel業(yè)務(wù)
    • 修改account_freeze表,凍結(jié)金額為0,state為2
    • 修改account表,恢復(fù)可用金額
  • 如何判斷是否空回滾?
    • cancel業(yè)務(wù)中,根據(jù)xid查詢account_freeze,如果為null則說明try還沒做,需要空回滾
  • 如何避免業(yè)務(wù)懸掛?
    • try業(yè)務(wù)中,根據(jù)xid查詢account_freeze ,如果已經(jīng)存在則證明Cancel已經(jīng)執(zhí)行,拒絕執(zhí)行try業(yè)務(wù)

接下來,我們改造account-service,利用TCC實(shí)現(xiàn)余額扣減功能。

2)聲明TCC接口

TCC的Try、Confirm、Cancel方法都需要在接口中基于注解來聲明,

我們?cè)赼ccount-service項(xiàng)目中的cn.itcast.account.service包中新建一個(gè)接口,聲明TCC三個(gè)接口:

package cn.itcast.account.service;

import io.seata.rm.tcc.api.BusinessActionContext;
import io.seata.rm.tcc.api.BusinessActionContextParameter;
import io.seata.rm.tcc.api.LocalTCC;
import io.seata.rm.tcc.api.TwoPhaseBusinessAction;

@LocalTCC
public interface AccountTCCService {

    @TwoPhaseBusinessAction(name = "deduct", commitMethod = "confirm", rollbackMethod = "cancel")
    void deduct(@BusinessActionContextParameter(paramName = "userId") String userId,
                @BusinessActionContextParameter(paramName = "money")int money);

    boolean confirm(BusinessActionContext ctx);

    boolean cancel(BusinessActionContext ctx);
}
3)編寫實(shí)現(xiàn)類

在account-service服務(wù)中的cn.itcast.account.service.impl包下新建一個(gè)類,實(shí)現(xiàn)TCC業(yè)務(wù):

package cn.itcast.account.service.impl;

import cn.itcast.account.entity.AccountFreeze;
import cn.itcast.account.mapper.AccountFreezeMapper;
import cn.itcast.account.mapper.AccountMapper;
import cn.itcast.account.service.AccountTCCService;
import io.seata.core.context.RootContext;
import io.seata.rm.tcc.api.BusinessActionContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Slf4j
public class AccountTCCServiceImpl implements AccountTCCService {

    @Autowired
    private AccountMapper accountMapper;
    @Autowired
    private AccountFreezeMapper freezeMapper;

    @Override
    @Transactional
    public void deduct(String userId, int money) {
        // 0.獲取事務(wù)id
        String xid = RootContext.getXID();
        // 1.扣減可用余額
        accountMapper.deduct(userId, money);
        // 2.記錄凍結(jié)金額,事務(wù)狀態(tài)
        AccountFreeze freeze = new AccountFreeze();
        freeze.setUserId(userId);
        freeze.setFreezeMoney(money);
        freeze.setState(AccountFreeze.State.TRY);
        freeze.setXid(xid);
        freezeMapper.insert(freeze);
    }

    @Override
    public boolean confirm(BusinessActionContext ctx) {
        // 1.獲取事務(wù)id
        String xid = ctx.getXid();
        // 2.根據(jù)id刪除凍結(jié)記錄
        int count = freezeMapper.deleteById(xid);
        return count == 1;
    }

    @Override
    public boolean cancel(BusinessActionContext ctx) {
        // 0.查詢凍結(jié)記錄
        String xid = ctx.getXid();
        AccountFreeze freeze = freezeMapper.selectById(xid);

        // 1.恢復(fù)可用余額
        accountMapper.refund(freeze.getUserId(), freeze.getFreezeMoney());
        // 2.將凍結(jié)金額清零,狀態(tài)改為CANCEL
        freeze.setFreezeMoney(0);
        freeze.setState(AccountFreeze.State.CANCEL);
        int count = freezeMapper.updateById(freeze);
        return count == 1;
    }
}

4.4.SAGA模式

Saga 模式是 Seata 即將開源的長(zhǎng)事務(wù)解決方案,將由螞蟻金服主要貢獻(xiàn)。

其理論基礎(chǔ)是Hector & Kenneth 在1987年發(fā)表的論文Sagas。

Seata官網(wǎng)對(duì)于Saga的指南:https://seata.io/zh-cn/docs/user/saga.html

4.4.1.原理

在 Saga 模式下,分布式事務(wù)內(nèi)有多個(gè)參與者,每一個(gè)參與者都是一個(gè)沖正補(bǔ)償服務(wù),需要用戶根據(jù)業(yè)務(wù)場(chǎng)景實(shí)現(xiàn)其正向操作和逆向回滾操作。

分布式事務(wù)執(zhí)行過程中,依次執(zhí)行各參與者的正向操作,如果所有正向操作均執(zhí)行成功,那么分布式事務(wù)提交。如果任何一個(gè)正向操作執(zhí)行失敗,那么分布式事務(wù)會(huì)去退回去執(zhí)行前面各參與者的逆向回滾操作,回滾已提交的參與者,使分布式事務(wù)回到初始狀態(tài)。

【高級(jí)篇】分布式事務(wù)

Saga也分為兩個(gè)階段:

  • 一階段:直接提交本地事務(wù)
  • 二階段:成功則什么都不做;失敗則通過編寫補(bǔ)償業(yè)務(wù)來回滾

4.4.2.優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

  • 事務(wù)參與者可以基于事件驅(qū)動(dòng)實(shí)現(xiàn)異步調(diào)用,吞吐高
  • 一階段直接提交事務(wù),無鎖,性能好
  • 不用編寫TCC中的三個(gè)階段,實(shí)現(xiàn)簡(jiǎn)單

缺點(diǎn):

  • 軟狀態(tài)持續(xù)時(shí)間不確定,時(shí)效性差
  • 沒有鎖,沒有事務(wù)隔離,會(huì)有臟寫

4.5.四種模式對(duì)比

我們從以下幾個(gè)方面來對(duì)比四種實(shí)現(xiàn):

  • 一致性:能否保證事務(wù)的一致性?強(qiáng)一致還是最終一致?
  • 隔離性:事務(wù)之間的隔離性如何?
  • 代碼侵入:是否需要對(duì)業(yè)務(wù)代碼改造?
  • 性能:有無性能損耗?
  • 場(chǎng)景:常見的業(yè)務(wù)場(chǎng)景

如圖:

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-lP7ly8dX-1686045878547)(assets/image-20210724185021819.png)]

5.高可用

Seata的TC服務(wù)作為分布式事務(wù)核心,一定要保證集群的高可用性。

5.1.高可用架構(gòu)模型

搭建TC服務(wù)集群非常簡(jiǎn)單,啟動(dòng)多個(gè)TC服務(wù),注冊(cè)到nacos即可。

但集群并不能確保100%安全,萬一集群所在機(jī)房故障怎么辦?所以如果要求較高,一般都會(huì)做異地多機(jī)房容災(zāi)。

比如一個(gè)TC集群在上海,另一個(gè)TC集群在杭州:

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-p7t5Pnw2-1686045878548)(assets/image-20210724185240957.png)]

微服務(wù)基于事務(wù)組(tx-service-group)與TC集群的映射關(guān)系,來查找當(dāng)前應(yīng)該使用哪個(gè)TC集群。當(dāng)SH集群故障時(shí),只需要將vgroup-mapping中的映射關(guān)系改成HZ。則所有微服務(wù)就會(huì)切換到HZ的TC集群了。

5.2.實(shí)現(xiàn)高可用

具體實(shí)現(xiàn)請(qǐng)參考《seata的部署和集成》文章來源地址http://www.zghlxwxcb.cn/news/detail-474087.html

到了這里,關(guān)于【高級(jí)篇】分布式事務(wù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 分布式:一文吃透分布式事務(wù)和seata事務(wù)

    分布式:一文吃透分布式事務(wù)和seata事務(wù)

    什么是事務(wù) 事務(wù)是并發(fā)控制的單位,是用戶定義的一個(gè)操作序列。 事務(wù)特性 原子性(Atomicity): 事務(wù)是數(shù)據(jù)庫(kù)的邏輯工作單位,事務(wù)中包括的諸操作要么全做,要么全不做。 一致性(Consistency): 事務(wù)執(zhí)行的結(jié)果必須是使數(shù)據(jù)庫(kù)從一個(gè)一致性狀態(tài)變到另一個(gè)一致性狀態(tài)。一致性

    2024年02月07日
    瀏覽(21)
  • 【分布式事務(wù)】Seata 開源的分布式事務(wù)解決方案

    【分布式事務(wù)】Seata 開源的分布式事務(wù)解決方案

    Seata 是一款開源的分布式事務(wù)解決方案,致力于提供高性能和簡(jiǎn)單易用的分布式事務(wù)服務(wù)。Seata 將為用戶提供了 AT、TCC、SAGA 和 XA 事務(wù)模式,為用戶打造一站式的分布式解決方案。 阿里巴巴作為國(guó)內(nèi)最早一批進(jìn)行應(yīng)用分布式(微服務(wù)化)改造的企業(yè),很早就遇到微服務(wù)架構(gòu)下

    2024年02月02日
    瀏覽(18)
  • 【分布式】分布式事務(wù):2PC

    【分布式】分布式事務(wù):2PC

    分布式事務(wù)的問題可以分為兩部分: 并發(fā)控制 concurrency control 原子提交 atomic commit 分布式事務(wù)問題的產(chǎn)生場(chǎng)景:一份數(shù)據(jù)被分片存在多臺(tái)服務(wù)器上,那么每次事務(wù)處理都涉及到了多臺(tái)機(jī)器。 可序列化(并發(fā)控制): 定義了事務(wù)執(zhí)行的正確性 真正地并行執(zhí)行事務(wù),獲得真正的

    2024年02月09日
    瀏覽(19)
  • Redis分布式鎖和分布式事務(wù)

    Redis分布式鎖和分布式事務(wù) 一、Redis分布式鎖 1.1 watch和事務(wù)實(shí)現(xiàn)分布式鎖 原理是通過watch來觀察一個(gè)變量,一個(gè)線程在操作的時(shí)候,其他線程會(huì)操作失敗,相當(dāng)于樂觀鎖。 1.2 setnx實(shí)現(xiàn)分布式鎖 原理是通過setnx設(shè)置一個(gè)變量,設(shè)置成功的線程搶到鎖,執(zhí)行相關(guān)的業(yè)務(wù),執(zhí)行完畢

    2024年02月09日
    瀏覽(25)
  • 分布式軟件架構(gòu)——分布式事務(wù)TCC和SAGA

    分布式軟件架構(gòu)——分布式事務(wù)TCC和SAGA

    TCC 是另一種常見的分布式事務(wù)機(jī)制,它是“ Try-Confirm-Cancel ”三個(gè)單詞的縮寫,是由數(shù)據(jù)庫(kù)專家 Pat Helland 在 2007 年撰寫的論文《Life beyond Distributed Transactions: An Apostate’s Opinion》中提出。 前面介紹的可靠消息隊(duì)列雖然能保證最終的結(jié)果是相對(duì)可靠的,過程也足夠簡(jiǎn)單(相對(duì)于

    2024年02月12日
    瀏覽(23)
  • 【分布式】java實(shí)現(xiàn)分布式事務(wù)的五種方案

    【分布式】java實(shí)現(xiàn)分布式事務(wù)的五種方案

    用戶支付完成會(huì)將支付狀態(tài)及訂單狀態(tài)保存在訂單數(shù)據(jù)庫(kù)中,由訂單服務(wù)去維護(hù)訂單數(shù)據(jù)庫(kù)。由庫(kù)存服務(wù)去維護(hù)庫(kù)存數(shù)據(jù)庫(kù)的信息。下圖是系統(tǒng)結(jié)構(gòu)圖: 如何實(shí)現(xiàn)兩個(gè)分布式服務(wù)(訂單服務(wù)、庫(kù)存服務(wù))共同完成一件事即訂單支付成功自動(dòng)減庫(kù)存,這里的關(guān)鍵是如何保證兩個(gè)

    2024年04月11日
    瀏覽(21)
  • 微服務(wù)·數(shù)據(jù)一致-事務(wù)與分布式事務(wù)

    微服務(wù)·數(shù)據(jù)一致-事務(wù)與分布式事務(wù)

    事務(wù)是計(jì)算機(jī)科學(xué)和數(shù)據(jù)庫(kù)管理中的一個(gè)關(guān)鍵概念,用于確保數(shù)據(jù)的一致性和可靠想。事務(wù)管理是大多數(shù)應(yīng)用程序和數(shù)據(jù)庫(kù)系統(tǒng)中不可或缺的一部分。分布式事務(wù)擴(kuò)展了事務(wù)的概念,用于多個(gè)分布式系統(tǒng)和服務(wù)的數(shù)據(jù)一致性管理。本調(diào)查報(bào)告將深入探討事務(wù)和分布式事務(wù)的概

    2024年02月09日
    瀏覽(20)
  • Seata分布式事務(wù)

    Seata分布式事務(wù)

    本地事務(wù),也就是傳統(tǒng)的單機(jī)事務(wù)。在傳統(tǒng)數(shù)據(jù)庫(kù)事務(wù)中,必須要滿足四個(gè)原則: 分布式事務(wù),就是指不是在單個(gè)服務(wù)或單個(gè)數(shù)據(jù)庫(kù)架構(gòu)下,產(chǎn)生的事務(wù),例如: 跨數(shù)據(jù)源的分布式事務(wù) 跨服務(wù)的分布式事務(wù) 綜合情況 完成上面的操作需要訪問三個(gè)不同的微服務(wù)和三個(gè)不同的

    2024年02月09日
    瀏覽(24)
  • Springboot分布式事務(wù)

    Springboot分布式事務(wù)

    1. 概念 本地事務(wù)是指事務(wù)的參與者、支持事務(wù)的服務(wù)器、資源服務(wù)器以及事務(wù)管理器位于同一節(jié)點(diǎn)相同數(shù)據(jù)庫(kù)上。 又稱為傳統(tǒng)事務(wù)。它是一個(gè)操作序列,這些操作要么都執(zhí)行,要么都不執(zhí)行,是一個(gè)不可分割的工作單位。例如,銀行轉(zhuǎn)賬工作:從一個(gè)帳號(hào)扣款并使另一個(gè)帳

    2024年02月09日
    瀏覽(24)
  • 分布式事務(wù) Seata

    分布式事務(wù) Seata

    事務(wù)(Transaction)是計(jì)算機(jī)科學(xué)中的一個(gè)重要概念,主要是指一個(gè) 完整的、不可分割的操作序列 。在關(guān)系型數(shù)據(jù)庫(kù)中,事務(wù)通常用于描述對(duì)數(shù)據(jù)庫(kù)進(jìn)行的一系列操作的執(zhí)行單元。 事務(wù)的ACID特性 : 原子性(Atomicity):事務(wù)是一個(gè)原子操作,要么全部執(zhí)行,要么全部回滾。如

    2024年02月17日
    瀏覽(23)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包