自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

分布式事務(wù),原理簡(jiǎn)單,寫(xiě)起來(lái)全是坑!

數(shù)據(jù)庫(kù) MySQL
Seata 中的 XA 模式實(shí)際上是基于 MySQL 的 XA 兩階段提交發(fā)展出來(lái)的,所以學(xué)習(xí) XA 模式,需要小伙伴們先理解 MySQL 中的 XA 是怎么一回事,把 MySQL 中的 XA 搞清楚了,再來(lái)學(xué)習(xí) Seata 中的 XA 模式就容易的多了。

今天我們就一起來(lái)看下另一種模式,XA 模式!

其實(shí)我覺(jué)得 seata 中的四種不同的分布式事務(wù)模式,學(xué)完 AT、TCC 以及 XA 就夠了,Saga 不好玩,而且長(zhǎng)事務(wù)本身就有很多問(wèn)題,也不推薦使用。

Seata 中的 XA 模式實(shí)際上是基于 MySQL 的 XA 兩階段提交發(fā)展出來(lái)的,所以學(xué)習(xí) XA 模式,需要小伙伴們先理解 MySQL 中的 XA 是怎么一回事,把 MySQL 中的 XA 搞清楚了,再來(lái)學(xué)習(xí) Seata 中的 XA 模式就容易的多了。

1. 什么是 XA 規(guī)范

1.1 什么是兩階段提交

我們先來(lái)稍微回顧一下兩階段提交。

先來(lái)看下面一張圖:

圖片

這張圖里涉及到三個(gè)概念:

  • AP:這個(gè)不用多說(shuō),AP 就是應(yīng)用程序本身。
  • RM:RM 是資源管理器,也就是事務(wù)的參與者,大部分情況下就是指數(shù)據(jù)庫(kù),一個(gè)分布式事務(wù)往往涉及到多個(gè) RM。
  • TM:TM 就是事務(wù)管理器,創(chuàng)建分布式事務(wù)并協(xié)調(diào)分布式事務(wù)中的各個(gè)子事務(wù)的執(zhí)行和狀態(tài),子事務(wù)就是指在 RM 上執(zhí)行的具體操作。

那么什么是兩階段(Two-Phase Commit, 簡(jiǎn)稱(chēng) 2PC)提交?

兩階段提交說(shuō)白了道理很簡(jiǎn)單,松哥舉個(gè)簡(jiǎn)單例子來(lái)和大家說(shuō)明兩階段提交:

比如下面一張圖:

圖片

我們?cè)?Business 中分別調(diào)用 Storage 與 Order、Account,這三個(gè)中的操作要同時(shí)成功或者同時(shí)失敗,但是由于這三個(gè)分處于不同服務(wù),因此我們只能先讓這三個(gè)服務(wù)中的操作各自執(zhí)行,三個(gè)服務(wù)中的事務(wù)各自執(zhí)行就是兩階段中的第一階段。

第一階段執(zhí)行完畢后,先不要急著提交,因?yàn)槿齻€(gè)服務(wù)中有的可能執(zhí)行失敗了,此時(shí)需要三個(gè)服務(wù)各自把自己一階段的執(zhí)行結(jié)果報(bào)告給一個(gè)事務(wù)協(xié)調(diào)者(也就是前面文章中的 Seata Server),事務(wù)協(xié)調(diào)者收到消息后,如果三個(gè)服務(wù)的一階段都執(zhí)行成功了,此時(shí)就通知三個(gè)事務(wù)分別提交,如果三個(gè)服務(wù)中有服務(wù)執(zhí)行失敗了,此時(shí)就通知三個(gè)事務(wù)分別回滾。

這就是所謂的兩階段提交。

總結(jié)一下:兩階段提交中,事務(wù)分為參與者(例如上圖的各個(gè)具體服務(wù))與協(xié)調(diào)者(上文案例中的 Seata Server),參與者將操作成敗通知協(xié)調(diào)者,再由協(xié)調(diào)者根據(jù)所有參與者的反饋情報(bào)決定各參與者是要提交操作還是中止操作,這里的參與者可以理解為 RM,協(xié)調(diào)者可以理解為 TM。

不過(guò) Seata 中的各個(gè)分布式事務(wù)模式,基本都是在二階段提交的基礎(chǔ)上演化出來(lái)的,因此并不完全一樣,這點(diǎn)需要小伙伴們注意。

1.2 什么是 XA 規(guī)范

XA 規(guī)范 是 X/Open 組織定義的分布式事務(wù)處理(DTP,Distributed Transaction Processing)標(biāo)準(zhǔn)。

XA 規(guī)范描述了全局的事務(wù)管理器與局部的資源管理器之間的接口。XA規(guī)范的目的是允許多個(gè)資源(如數(shù)據(jù)庫(kù),應(yīng)用服務(wù)器,消息隊(duì)列等)在同一事務(wù)中訪問(wèn),這樣可以使 ACID 屬性跨越應(yīng)用程序而保持有效。

XA 規(guī)范使用兩階段提交來(lái)保證所有資源同時(shí)提交或回滾任何特定的事務(wù)。

XA 規(guī)范在上世紀(jì) 90 年代初就被提出。目前,幾乎所有主流的數(shù)據(jù)庫(kù)都對(duì) XA 規(guī)范提供了支持。

XA 事務(wù)的基礎(chǔ)是兩階段提交協(xié)議。需要有一個(gè)事務(wù)協(xié)調(diào)者來(lái)保證所有的事務(wù)參與者都完成了準(zhǔn)備工作(第一階段)。如果協(xié)調(diào)者收到所有參與者都準(zhǔn)備好的消息,就會(huì)通知所有的事務(wù)都可以提交了(第二階段)。MySQL 在這個(gè) XA 事務(wù)中扮演的是參與者的角色,而不是協(xié)調(diào)者(事務(wù)管理器)。

MySQL 的 XA 事務(wù)分為內(nèi)部 XA 和外部 XA。外部 XA 可以參與到外部的分布式事務(wù)中,需要應(yīng)用層介入作為協(xié)調(diào)者;內(nèi)部 XA 事務(wù)用于同一實(shí)例下跨多引擎事務(wù),由 Binlog 作為協(xié)調(diào)者,比如在一個(gè)存儲(chǔ)引擎提交時(shí),需要將提交信息寫(xiě)入二進(jìn)制日志,這就是一個(gè)分布式內(nèi)部 XA 事務(wù),只不過(guò)二進(jìn)制日志的參與者是 MySQL 本身。MySQL 在 XA 事務(wù)中扮演的是一個(gè)參與者的角色,而不是協(xié)調(diào)者。

2. MySQL 中的 XA

接下來(lái)松哥通過(guò)一個(gè)簡(jiǎn)單的例子先給大家看下 MySQL 中的 XA 是怎么玩的。

2.1 兩階段事務(wù)提交

比如說(shuō)轉(zhuǎn)賬操作,我用 MySQL 中的 XA 事務(wù)來(lái)和大家演示一下從一個(gè)賬戶中轉(zhuǎn)出 10 塊錢(qián):

圖片

上面這段事務(wù)提交是一個(gè)兩階段事務(wù)提交的案例。

具體執(zhí)行步驟如下:

  • XA START "transfer_money":這個(gè)表示開(kāi)啟一個(gè) XA 事務(wù),后面的字符串是事務(wù)的 xid,這是一個(gè)唯一字符串,開(kāi)啟之后,事務(wù)的狀態(tài)變?yōu)锳CTIVE。
  • update account set amount=amount-10 where account_no='A'; 這個(gè)表示執(zhí)行具體的 SQL。
  • XA END "transfer_money":這個(gè)表示結(jié)束一個(gè) XA 事務(wù),此時(shí)事務(wù)的狀態(tài)轉(zhuǎn)為IDLE。
  • XA PREPARE "transfer_money":這個(gè)將事務(wù)置為 PREPARE 狀態(tài)。
  • XA COMMIT "transfer_money":這個(gè)用來(lái)提交事務(wù),提交之后,事務(wù)的狀態(tài)就是 COMMITED。

最后一步,可以通過(guò) XA COMMIT 來(lái)提交,也可以通過(guò) XA ROLLBACK 來(lái)回滾,回滾后事務(wù)的狀態(tài)就是 ROLLBACK。

另外第四步可以省略,即一個(gè) IDLE 狀態(tài)的 XA 事務(wù)可以直接提交或者回滾。

我們來(lái)看下面一張流程圖:

圖片

從這張圖里我們可以看出,事務(wù)可以一步提交,也可以兩階段提交,都是支持的。如果是兩階段提交,prepare 之后,其實(shí)是在等其他的資源管理器(RM)反饋結(jié)果。

2.2 事務(wù)直接提交

松哥再給大家演示一下事務(wù)一步提交:

圖片

這個(gè)就比較簡(jiǎn)單,沒(méi)啥好說(shuō)的。

這塊再跟大家介紹另外一個(gè) XA 事務(wù)相關(guān)的命令 XA RECOVER,如下圖:

圖片

XA RECOVER 可以列出所有處于 PREPARE 狀態(tài)的 XA 事務(wù),其他狀態(tài)的事務(wù)則都不會(huì)列出來(lái),如上圖。

2.3 事務(wù)回滾

再舉一個(gè)事務(wù)回滾的例子:

圖片

小伙伴們看到,xa recover 可以查看處于 prepare 狀態(tài)的事務(wù),事務(wù)回滾有三個(gè)參數(shù):第一個(gè)參數(shù),是以 gtrid_length 為依據(jù),從 data 字符串上截取下來(lái)的值;第二個(gè)參數(shù),是第一個(gè)從 data 上截取下來(lái)值之后,data 剩余的值,在本案例中,第一次被截取之后,就不剩了,所以第二個(gè)參數(shù)是一個(gè)空字符串;第三個(gè)參數(shù)是 formatID 的值。

回滾之后,再執(zhí)行 xa recover 就看不到東西了。

2.4 小結(jié)

在用一個(gè)客戶端環(huán)境下,XA 事務(wù)和本地(非 XA )事務(wù)互相排斥,如果已經(jīng)通過(guò) XA START 來(lái)開(kāi)啟一個(gè)事務(wù),則本地事務(wù)不會(huì)被啟動(dòng),直到 XA 事務(wù)被提交或者被回滾為止。

相反的,如果已經(jīng)使用 START TRANSACTION 啟動(dòng)一個(gè)本地事務(wù),則 XA 語(yǔ)句不能被使用,直到該事務(wù)被提交或者回滾為止,而且 XA 事務(wù)僅僅被 InnoDB 存儲(chǔ)引擎支持。

3. Seata 中的 XA

3.1 Seata 中的 XA 模式

我們先來(lái)看一點(diǎn)理論知識(shí),3.3 小節(jié)我們?cè)賮?lái)看代碼實(shí)踐。

通過(guò)上面的介紹,大家已經(jīng)知道了 MySQL 中的 XA 事務(wù)是怎么回事了,Seata 中的 XA 模式其實(shí)就是在 MySQL 中 XA 模式的基礎(chǔ)上實(shí)現(xiàn)的。Seata 中的 XA 模式就是在 Seata 定義的分布式事務(wù)框架內(nèi),利用事務(wù)資源(數(shù)據(jù)庫(kù)、消息服務(wù)等)對(duì) XA 協(xié)議的支持,以 XA 協(xié)議的機(jī)制來(lái)管理分支事務(wù)的一種事務(wù)模式。

我們來(lái)看下面一張圖:

圖片

我來(lái)大概說(shuō)一下這個(gè)執(zhí)行步驟:

  • 首先由 TM 開(kāi)啟全局分布式事務(wù)。
  • 各個(gè)業(yè)務(wù) SQL 分別放在不同的 XA 分支中進(jìn)行,具體執(zhí)行的流程就是XA Start->業(yè)務(wù) SQL->XA End,這個(gè)流程跟我 2.1 小節(jié)和大家演示的 MySQL 中 XA 事務(wù)的流程是一致的。
  • 分支中的 XA 事務(wù)執(zhí)行完成后,執(zhí)行XA prepare,并將自己執(zhí)行的狀態(tài)報(bào)告給 TC。
  • 其他的分支事務(wù)均按照 2、3 步驟來(lái)執(zhí)行。
  • 當(dāng)所有分支事務(wù)都執(zhí)行完畢后,TC 也收到了各個(gè)分支事務(wù)報(bào)告上來(lái)的執(zhí)行狀態(tài),如果所有狀態(tài)都 OK,則 TC 通知所有 RM 執(zhí)行XA Commit 完成事務(wù)的最終提交,否則 TC 通知所有 RM 執(zhí)行XA Rollback 進(jìn)行事務(wù)回滾。

這就是 Seata 中的 XA 模式!只要小伙伴們理解了 2.2 小節(jié)中 MySQL 的 XA 模式,那么 Seata 中的 XA 模式就很好理解了。

3.2 特色

前面小伙伴們已經(jīng)學(xué)會(huì)了 AT 和 TCC 兩種不同的分布式事務(wù)模式了,現(xiàn)在再加入一個(gè) XA,我們?cè)賮?lái)把這三個(gè)放在一起比較下。

  • AT 和 TCC 都是通過(guò)反向補(bǔ)償將數(shù)據(jù)復(fù)原的,也就是說(shuō),通過(guò)一條更新語(yǔ)句將數(shù)據(jù)復(fù)原;XA 因?yàn)槭?MySQL 自己的功能,所以不是反向補(bǔ)償,而是正兒八經(jīng)的回滾(處于 prepare 狀態(tài)的數(shù)據(jù)并沒(méi)有 commit,將來(lái)在二階段可以選擇 commit 或者 rollback)。
  • AT 和 XA 模式是無(wú)侵入的分布式事務(wù)解決方案,適用于不希望對(duì)業(yè)務(wù)進(jìn)行改造的場(chǎng)景,幾乎0學(xué)習(xí)成本;TCC 則有一定的代碼侵入。
  • AT 和 XA 都是一種全自動(dòng)的,無(wú)論是提交呀,回滾呀(無(wú)論是真回滾還是反向補(bǔ)償),都是全自動(dòng)的,就是開(kāi)發(fā)者基本上不需要額外做什么事情;TCC 則是一種手動(dòng)的分布式事務(wù),一階段的 prepare、二階段的 commit 或者 rollback,所有邏輯都是開(kāi)發(fā)者自己寫(xiě)的。
  • 松哥發(fā)前面文章的時(shí)候,有小伙伴提到分布式事務(wù)的一致性問(wèn)題,XA 模式是分布式強(qiáng)一致性的解決方案,但是因?yàn)樾阅艿投鴮?dǎo)致使用較少。

好啦,比較完啦,那就上代碼吧!

3.3 代碼實(shí)踐

小伙伴們只需要搞明白前面的 AT 模式后,XA 模式其實(shí)跟 AT 模式差不多!就是替換一下數(shù)據(jù)源即可!話是這么說(shuō),不過(guò)真做起來(lái),還是有很多坑,我們一起來(lái)看下。

為了方便大家理解,本文我就不重新搞案例了,咱們還用上篇文章那個(gè)下訂單的案例來(lái)演示。

這是一個(gè)商品下單的案例,一共有五個(gè)服務(wù),我來(lái)和大家稍微解釋下:

eureka:這是服務(wù)注冊(cè)中心。

account:這是賬戶服務(wù),可以查詢/修改用戶的賬戶信息(主要是賬戶余額)。

order:這是訂單服務(wù),可以下訂單。

storage:這是一個(gè)倉(cāng)儲(chǔ)服務(wù),可以查詢/修改商品的庫(kù)存數(shù)量。

bussiness:這是業(yè)務(wù),用戶下單操作將在這里完成。

這個(gè)案例講了一個(gè)什么事呢?

當(dāng)用戶想要下單的時(shí)候,調(diào)用了 bussiness 中的接口,bussiness 中的接口又調(diào)用了它自己的 service,在 service 中,首先開(kāi)啟了全局分布式事務(wù),然后通過(guò) feign 調(diào)用 storage 中的接口去扣庫(kù)存,然后再通過(guò) feign 調(diào)用 order 中的接口去創(chuàng)建訂單(order 在創(chuàng)建訂單的時(shí)候,不僅會(huì)創(chuàng)建訂單,還會(huì)扣除用戶賬戶的余額),在這個(gè)過(guò)程中,如果有任何一個(gè)環(huán)節(jié)出錯(cuò)了(余額不足、庫(kù)存不足等導(dǎo)致的問(wèn)題),就會(huì)觸發(fā)整體的事務(wù)回滾。

本案例具體架構(gòu)如下圖:

圖片

這個(gè)案例就是一個(gè)典型的分布式事務(wù)問(wèn)題,storage、order 以及 account 中的事務(wù)分屬于不同的微服務(wù),但是我們希望他們同時(shí)成功或者同時(shí)失敗。

這個(gè)案例的基本架構(gòu)我這里就不重復(fù)搭建了,小伙伴們可以參考上篇文章,這里我們主要來(lái)看 XA 事務(wù)如何添加進(jìn)來(lái)。

3.3.1 數(shù)據(jù)庫(kù)配置

由于 XA 模式利用的是 MySQL 自身對(duì) XA 規(guī)范的實(shí)現(xiàn),所以 XA 機(jī)制實(shí)際上是不需要 undo_log 表的,小伙伴們可以把你 AT 模式中的 undo_log 表刪除啦~ 如果刪除后運(yùn)行 Java 程序報(bào)錯(cuò),那說(shuō)明你的 XA 模式使用的不地道!注意看松哥后面的講解哦。

接下來(lái)我就來(lái)說(shuō)幾個(gè)要點(diǎn)。

數(shù)據(jù)庫(kù)驅(qū)動(dòng)

這是一個(gè)坑。松哥經(jīng)過(guò)反復(fù)測(cè)試,seata 中的 XA 模式和最新版的 MySQL 驅(qū)動(dòng)不兼容,運(yùn)行時(shí)候會(huì)有錯(cuò)誤,經(jīng)過(guò)測(cè)試,MySQL 8.0.11 這個(gè)版本的驅(qū)動(dòng)是沒(méi)問(wèn)題的,所以在 account、storage 以及 order 三個(gè)需要數(shù)據(jù)庫(kù)調(diào)用的服務(wù)上,記得修改一下數(shù)據(jù)庫(kù)驅(qū)動(dòng)依賴(lài)的版本號(hào):

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
<version>8.0.11</version>
</dependency>

druid 依賴(lài)

有的小伙伴們看到這里用到了阿里的 Druid 數(shù)據(jù)庫(kù)連接池,就趕緊加入這個(gè)依賴(lài)!殊不知,這又掉入版本兼容的坑了,spring-cloud-starter-alibaba-seata 依賴(lài)中實(shí)際上包含了 druid 依賴(lài),而且版本號(hào)是沒(méi)有問(wèn)題的!所以小伙伴們千萬(wàn)別自己手動(dòng)加 druid 依賴(lài),可能會(huì)因?yàn)榘姹咎?hào)問(wèn)題掉坑。

關(guān)掉數(shù)據(jù)源代碼

接下來(lái)就是關(guān)閉掉 seata 數(shù)據(jù)源代理了,account、storage 以及 order 里邊都改一下,加入如下配置:

seata.enable-auto-data-source-proxy=false

配置自定義數(shù)據(jù)源

接下來(lái)就是配置自定義數(shù)據(jù)源了,account、order 以及 storage 都要配置,如下:

@Configuration
public class DataSourceConfiguration {

@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource druidDataSource() {
return new DruidDataSource();
}

@Bean("dataSourceProxy")
@Primary
public DataSource dataSource(DruidDataSource druidDataSource) {
return new DataSourceProxyXA(druidDataSource);
}


@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSourceProxy)throws Exception{
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSourceProxy);
sqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory());
return sqlSessionFactoryBean.getObject();
}

}

先配置 DruidDataSource,但這不是我們最終目的,最終目的是配置 DataSourceProxyXA,看名字就知道,這就會(huì)把事務(wù)切換為 XA 模式,最后,還需要基于 DataSourceProxyXA 來(lái)配置一下 MyBatis,都是常規(guī)操作,不多說(shuō)。

責(zé)任編輯:武曉燕 來(lái)源: 江南一點(diǎn)雨
相關(guān)推薦

2022-06-21 08:27:22

Seata分布式事務(wù)

2020-03-31 08:05:23

分布式開(kāi)發(fā)技術(shù)

2021-06-10 06:57:39

Redis存儲(chǔ)數(shù)據(jù)庫(kù)

2022-07-10 20:24:48

Seata分布式事務(wù)

2022-06-27 08:21:05

Seata分布式事務(wù)微服務(wù)

2025-01-15 08:34:00

分布式事務(wù)服務(wù)

2023-09-14 15:44:46

分布式事務(wù)數(shù)據(jù)存儲(chǔ)

2017-07-26 15:08:05

大數(shù)據(jù)分布式事務(wù)

2019-10-10 09:16:34

Zookeeper架構(gòu)分布式

2009-06-19 15:28:31

JDBC分布式事務(wù)

2021-09-29 09:07:37

分布式架構(gòu)系統(tǒng)

2009-09-18 15:10:13

分布式事務(wù)LINQ TO SQL

2019-08-19 10:24:33

分布式事務(wù)數(shù)據(jù)庫(kù)

2024-01-26 13:17:00

rollbackMQ訂單系統(tǒng)

2022-08-26 00:02:03

RocketMQ單體架構(gòu)MQ

2025-04-29 04:00:00

分布式事務(wù)事務(wù)消息

2019-06-26 09:41:44

分布式事務(wù)微服務(wù)

2022-03-24 07:51:27

seata分布式事務(wù)Java

2024-06-07 08:06:36

2021-08-06 08:33:27

Springboot分布式Seata
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)