新聞中心
前言
在上一節(jié)中我們講解了,關(guān)于分布式事務(wù)和seata的基本介紹和使用,感興趣的小伙伴可以回顧一下??《別再說你不知道分布式事務(wù)了!》?? 最后小農(nóng)也說了,下期會帶給大家關(guān)于Seata中關(guān)于seata中AT、TCC、SAGA 和 XA 模式的介紹和使用,今天就來講解關(guān)于Seata中分布式四種模型的介紹。

創(chuàng)新互聯(lián)建站是一家專注于成都網(wǎng)站制作、成都網(wǎng)站設(shè)計與策劃設(shè)計,沁水網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)建站做網(wǎng)站,專注于網(wǎng)站建設(shè)十載,網(wǎng)設(shè)計領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:沁水等地區(qū)。沁水做網(wǎng)站價格咨詢:18980820575
Seata分為三大模塊,分別是 TM、RM 和 TC。
TC (Transaction Coordinator) - 事務(wù)協(xié)調(diào)者:維護全局和分支事務(wù)的狀態(tài),驅(qū)動全局事務(wù)提交或回滾。
TM (Transaction Manager) - 事務(wù)管理器:定義全局事務(wù)的范圍:開始全局事務(wù)、提交或回滾全局事務(wù)。
RM (Resource Manager) - 資源管理器:管理分支事務(wù)處理的資源,與TC交談以注冊分支事務(wù)和報告分支事務(wù)的狀態(tài),并驅(qū)動分支事務(wù)提交或回滾。
在 Seata 中,分布式事務(wù)的執(zhí)行流程:
- TM 開啟分布式事務(wù)(TM 向 TC 注冊全局事務(wù)記錄)。
- 按業(yè)務(wù)場景,編排數(shù)據(jù)庫、服務(wù)等事務(wù)內(nèi)資源(RM 向 TC 匯報資源準備狀態(tài) )。
- TM 結(jié)束分布式事務(wù),事務(wù)一階段結(jié)束(TM 通知 TC 提交/回滾分布式事務(wù))。
- TC 匯總事務(wù)信息,決定分布式事務(wù)是提交還是回滾。
- TC 通知所有 RM 提交/回滾 資源,事務(wù)二階段結(jié)束。
TM 和 RM 是作為 Seata 的客戶端與業(yè)務(wù)系統(tǒng)集成在一起,TC 作為 Seata 的服務(wù)端獨立部署。
服務(wù)端存儲模式支持三種:
file: 單機模式,全局事務(wù)會話信息內(nèi)存中讀寫并持久化本地文件root.data,性能較高(默認)。
DB: 高可用模式,全局事務(wù)會話信息通過DB共享,相對性能差一些。
redis: Seata-Server1.3及以上版本支持,性能較高,存在事務(wù)信息丟失風(fēng)險,需要配合實際場景使用。
TC環(huán)境搭建詳解
這里我們使用DB高可用模式,找到conf/file.conf文件。
修改以上中的信息,找到對應(yīng)的db配置,修改其中的jdbc連接,要注意其中涉及到三個表(global_table,branch_table,lock_table),同時 mysql5和mysql8的驅(qū)動是不一樣的。
mysql5:com.mysql.jdbc.Driver。
mysql8:com.mysql.cj.jdbc.Driver。
建表語句地址:https://github.com/seata/seata/blob/develop/script/server/db/mysql.sql。
global_table: 全局事務(wù)表,每當有一個全局事務(wù)發(fā)起后,就會在該表中記錄全局事務(wù)的ID。
branch_table: 分支事務(wù)表,記錄每一個分支事務(wù)的 ID,分支事務(wù)操作的哪個數(shù)據(jù)庫等信息。
lock_table: 全局鎖。
當上述配置好以后,重啟Seata即可生效。
Seata 配置 Nacos
Seata支持注冊服務(wù)到Nacos,以及支持Seata所有配置放到Nacos配置中心,在Nacos中統(tǒng)一維護;在 高可用模式下就需要配合Nacos來完成
首先找到 conf/registry.conf,修改registry信息。
registry {
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "nacos"
nacos {
application = "seata-server" # 這里的配置要和客戶端保持一致
serverAddr = "127.0.0.1:8848"
group = "SEATA_GROUP" # 這里的配置要和客戶端保持一致
namespace = ""
cluster = "default"
username = "nacos"
password = "nacos"
}
config {
# file、nacos 、apollo、zk、consul、etcd3
type = "nacos"
nacos {
serverAddr = "127.0.0.1:8848"
namespace = ""
group = "SEATA_GROUP"
username = "nacos"
password = "nacos"
dataId = "seataServer.properties"
}
......
}修改好后,將seata中的一些配置上傳到Nacos中,因為配置項比較多,所以官方提供了一個config.txt,只下載并且修改其中某些參數(shù)后,上傳到Nacos中即可。
下載地址:https://github.com/seata/seata/tree/develop/script/config-center。
修改項如下:
service.vgroupMapping.mygroup=default # 事務(wù)分組
store.mode=db
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
store.db.user=root
store.db.password=123456
修改好這個文件以后,把這個文件放到seata目錄下:
把這些配置都加入到Nacos配置中,要借助一個腳本來進行執(zhí)行,官方已經(jīng)提供好。
地址為:https://github.com/seata/seata/blob/develop/script/config-center/nacos/nacos-config.sh。
新建一個nacos-config.sh文件,將腳本內(nèi)容復(fù)制進去,修改congfig.txt的路徑。
上述文件修改好后,打開git工具,將nacos-config.sh工具拖拽到窗體中即可或者使用命令。
sh nacos-config.sh -h 127.0.0.1 -p 8848 -g SEATA_GROUP -t 88b8f583-43f9-4272-bd46-78a9f89c56e8 -u nacos -w nacos。
-h:nacos地址。
-p:端口,默認8848。
-g:seata的服務(wù)列表分組名稱。
-t:nacos命名空間id。
-u和-w:nacos的用戶名和密碼。
最后會有四個執(zhí)行失敗,是因為redis報錯的關(guān)系,這個可以忽略,不影響正常使用。最后可以看到在Nacos中有很多的配置項,說明導(dǎo)入成功。再重新其中seata,成功監(jiān)聽到8091端口,表示前置工作都已經(jīng)準備完成。
Seata的事務(wù)模式
Seata 定義了全局事務(wù)的框架,主要分為以下幾步:
- TM 向 TC請求 發(fā)起(Begin)、提交(Commit)、回滾(Rollback)等全局事務(wù)。
- TM把代表全局事務(wù)的XID綁定到分支事務(wù)上。
- RM向TC注冊,把分支事務(wù)關(guān)聯(lián)到XID代表的全局事務(wù)中。
- RM把分支事務(wù)的執(zhí)行結(jié)果上報給TC。
- TC發(fā)送分支提交(Branch Commit)或分支回滾(Branch Rollback)命令給RM。
Seata 的 全局事務(wù) 處理過程,分為兩個階段:
- 執(zhí)行階段 :執(zhí)行分支事務(wù),并保證執(zhí)行結(jié)果滿足是可回滾的(Rollbackable)和持久化的(Durable)。
- 完成階段:根據(jù) 執(zhí)行階段 結(jié)果形成的決議,應(yīng)用通過 TM 發(fā)出的全局提交或回滾的請求給 TC,TC 命令 RM 驅(qū)動 分支事務(wù) 進行 Commit 或 Rollback。
Seata 的所謂事務(wù)模式是指:運行在 Seata 全局事務(wù)框架下的 分支事務(wù) 的行為模式。準確地講,應(yīng)該叫作 分支事務(wù)模式。
不同的 事務(wù)模式 區(qū)別在于 分支事務(wù) 使用不同的方式達到全局事務(wù)兩個階段的目標。即,回答以下兩個問題:
- 執(zhí)行階段 :如何執(zhí)行并 保證 執(zhí)行結(jié)果滿足是可回滾的(Rollbackable)和持久化的(Durable)。
- 完成階段:收到 TC 的命令后,如何做到分支的提交或回滾?
我們以AT模式為例:
- 執(zhí)行階段:
- 可回滾:根據(jù) SQL 解析結(jié)果,記錄回滾日志
- 持久化:回滾日志和業(yè)務(wù) SQL 在同一個本地事務(wù)中提交到數(shù)據(jù)庫
- 完成階段:
- 分支提交:異步刪除回滾日志記錄
- 分支回滾:依據(jù)回滾日志進行反向補償更新
接下來就進入重頭戲,Seata四大模式的介紹。
Seata-XA模式
Seata 1.2.0 版本發(fā)布了新的事務(wù)模型:XA模式,實現(xiàn)了對XA協(xié)議的支持。對于XA模式我們需要從三個點去解析它。
- XA模式是什么。
- 為什么支持XA。
- XA模式如何實現(xiàn)和使用。
XA模式簡介
首先需要知道XA模型是什么,XA 規(guī)范早在上世紀 90 年代初就被提出,用于解決分布式事務(wù)領(lǐng)域的問題,他也是最早的分布式事務(wù)處理方案,因為需要數(shù)據(jù)庫內(nèi)部也是支持XA模式的,比如MYSQL,XA模式具有強一致性的特點,因此他對數(shù)據(jù)庫占用時間比較長,所以性能比較低。
XA模式屬于兩階段提交。
- 第一階段進行事務(wù)注冊,將事務(wù)注冊到TC中,執(zhí)行SQL語句。
- 第二階段TC判斷無事務(wù)出錯,通知所有事務(wù)提交,否則回滾。
- 在第一到第二階段過程中,事務(wù)一直占有數(shù)據(jù)庫鎖,因此性能比較低,但是所有事務(wù)要么一起提交,要么一起回滾,所以能實現(xiàn)強一致性。
無論是AT模式、TCC還是SAGA,這些模式的提出,都是源于XA規(guī)范對某些業(yè)務(wù)場景無法滿足。
什么是XA協(xié)議
XA規(guī)范是X/OPEN組織定義的分布式事務(wù)處理(DTP,Distributed Transaction Processing)標準,XA規(guī)范描述了全局事務(wù)管理器和局部資源管理器之間的接口,XA規(guī)范的目的是允許多個資源(如數(shù)據(jù)庫,應(yīng)用服務(wù)器,消息隊列等)在同一事務(wù)中訪問,這樣可以使 ACID 屬性跨越應(yīng)用程序而保持有效。
XA 規(guī)范 使用兩階段提交(2PC,Two-Phase Commit)來保證所有資源同時提交或回滾任何特定的事務(wù)。因為XA規(guī)范最早被提出,所以幾乎所有的主流數(shù)據(jù)庫都保有對XA規(guī)范的支持。
分布式事務(wù)DTP模型定義的角色如下:
- AP:即應(yīng)用程序,可以理解為使用DTP分布式事務(wù)的程序,例如訂單服務(wù)、庫存服務(wù)。
- RM:資源管理器,可以理解為事務(wù)的參與者,一般情況下是指一個數(shù)據(jù)庫的實例(MySql),通過資源管理器對該數(shù)據(jù)庫進行控制,資源管理器控制著分支事務(wù)。
- TM:事務(wù)管理器,負責(zé)協(xié)調(diào)和管理事務(wù),事務(wù)管理器控制著全局事務(wù),管理實務(wù)生命周期,并協(xié)調(diào)各個RM。全局事務(wù)是指分布式事務(wù)處理環(huán)境中,需要操作多個數(shù)據(jù)庫共同完成一個工作,這個工作即是一個全局事務(wù)。
DTP模式定義TM和RM之間通訊的接口規(guī)范叫XA,簡單理解為數(shù)據(jù)庫提供的2PC接口協(xié)議,基于數(shù)據(jù)庫的XA協(xié)議來實現(xiàn)的2PC又稱為XA方案。
現(xiàn)在有應(yīng)用程序(AP)持有訂單庫和庫存庫,應(yīng)用程序(AP)通過TM通知訂單庫(RM)和庫存庫(RM),進行扣減庫存和生成訂單,這個時候RM并沒有提交事務(wù),而且鎖定資源。
當TM收到執(zhí)行消息,如果有一方RM執(zhí)行失敗,分別向其他RM也發(fā)送回滾事務(wù),回滾完畢,釋放鎖資源。
當TM收到執(zhí)行消息,RM全部成功,向所有RM發(fā)起提交事務(wù),提交完畢,釋放鎖資源。
分布式通信協(xié)議XA規(guī)范,具體執(zhí)行流程如下所示:
第一步:AP創(chuàng)建了RM1,RM2的JDBC連接。
第二步:AP通知生成全局事物ID,并把RM1,RM2注冊到全局事務(wù)ID。
第三步:執(zhí)行二階段協(xié)議中的第一階段prepare。
第四步:根據(jù)prepare請求,決定整體提交或回滾。
但是對于XA而言,如果一個參與全局事務(wù)的資源“失聯(lián)”了,那么就意味著TM收不到分支事務(wù)結(jié)束的命令,那么它鎖定的數(shù)據(jù),將會一直被鎖定,從而產(chǎn)生死鎖,這個也是Seata需要重點解決的問題。
在Seata定義的分布式事務(wù)架構(gòu)中,利用事務(wù)資源(數(shù)據(jù)局、消息)等對XA協(xié)議進行支持,用XA協(xié)議的機制來管理分支事務(wù)。
- 執(zhí)行階段:
- 可回滾:業(yè)務(wù)SQL操作在XA分支中進行,有資源管理器對XA協(xié)議的支持來保證可回滾。
- 持久化:ZA分支完成以后,執(zhí)行 XA prepare,同樣,由資源對XA協(xié)議的支持來保證持久化。
- 完成階段:
XA存在的意義
- 分支提交:執(zhí)行XA分支的commit。
- 分支回滾:執(zhí)行XA分支的rollback。
Seata 已經(jīng)支持了三大事務(wù)模式:AT\TCC\SAGA,這三個都是補償型事務(wù),補償型事務(wù)處理你機制構(gòu)建在 事務(wù)資源 之上(要么中間件層面,要么應(yīng)用層),事務(wù)資源本身對于分布式的事務(wù)是無感知的,這種對于分布式事務(wù)的無感知存在有一個根本性的問題,無法做到真正的全局一致性。
例如一個庫存記錄,在補償型事務(wù)處理過程中,用80扣減為60,這個時候倉庫管理員查詢數(shù)據(jù)結(jié)果,看到的是60,之后因為異?;貪L,庫存回滾到原來的80,那么這個時候庫存管理員看到的60,其實就是臟數(shù)據(jù),而這個中間狀態(tài)就是補償型事務(wù)存在的臟數(shù)據(jù)。
和補償型事務(wù)不同,XA協(xié)議要求事務(wù)資源 本身提供對規(guī)范和協(xié)議的支持,因為事務(wù)資源感知并參與分布式事務(wù)處理過程中,所以事務(wù)資源可以保證從任意視角對數(shù)據(jù)的訪問有效隔離性,滿足全局數(shù)據(jù)的一致性。
XA模式的使用
官方案例:https://github.com/seata/seata-samples。
項目名:seata-samples。
業(yè)務(wù)開始:business-xa庫存服務(wù):stock-xa訂單服務(wù):order-xa賬號服務(wù):account-xa。
把這個項目案例下載下來以后,找到項目名為seata-xa的目錄,里面有測試數(shù)據(jù)庫的鏈接,如果不想用測試數(shù)據(jù)庫,只需要修改官方文檔中數(shù)據(jù)庫配置信息即可。
首先關(guān)注的是 business-xa項目,更多的關(guān)注BusinessService.purchase()方法。
@GlobalTransactional
public void purchase(String userId, String commodityCode, int orderCount, boolean rollback) {
String xid = RootContext.getXID();
LOGGER.info("New Transaction Begins: " + xid);
//調(diào)用庫存減庫存
String result = stockFeignClient.deduct(commodityCode, orderCount);
if (!SUCCESS.equals(result)) {
throw new RuntimeException("庫存服務(wù)調(diào)用失敗,事務(wù)回滾!");
}
//生成訂單
result = orderFeignClient.create(userId, commodityCode, orderCount);
if (!SUCCESS.equals(result)) {
throw new RuntimeException("訂單服務(wù)調(diào)用失敗,事務(wù)回滾!");
}
if (rollback) {
throw new RuntimeException("Force rollback ... ");
}
}
其實現(xiàn)方法較之前差不多,我們只需要在order-xa里面(OrderService.create),添加人為錯誤(int i = 1/0;)。
public void create(String userId, String commodityCode, Integer count) {
String xid = RootContext.getXID();
LOGGER.info("create order in transaction: " + xid);
int i = 1/0;
// 定單總價 = 訂購數(shù)量(count) * 商品單價(100)
int orderMoney = count * 100;
// 生成訂單
jdbcTemplate.update("insert order_tbl(user_id,commodity_code,count,money) values(?,?,?,?)",
new Object[] {userId, commodityCode, count, orderMoney});
// 調(diào)用賬戶余額扣減
String result = accountFeignClient.reduce(userId, orderMoney);
if (!SUCCESS.equals(result)) {
throw new RuntimeException("Failed to call Account Service. ");
}
}里面有一個方法可以進行XA模式和AT模式的轉(zhuǎn)換OrderXADataSourceConfiguration.dataSource。
@Bean("dataSourceProxy")
public DataSource dataSource(DruidDataSource druidDataSource) {
// DataSourceProxy for AT mode
// return new DataSourceProxy(druidDataSource);
// DataSourceProxyXA for XA mode
return new DataSourceProxyXA(druidDataSource);
}我們啟動這四個服務(wù),訪問地址 http://localhost:8084/purchase。
我們可以其中報錯,然后再去看對應(yīng)數(shù)據(jù)庫的數(shù)據(jù),沒有發(fā)生更改,說明我們的XA模式生效了,當你dubug去看里面的庫存服務(wù)的時候,當操作數(shù)據(jù)更改的時候,數(shù)據(jù)庫里面其實也是沒有記錄的,因為XA是強一致性,只有當事務(wù)結(jié)束完成以后,才會更改其中的數(shù)據(jù)。
XA模式的加入,補齊了Seata在全局一致性場景下的缺口,形成了AT、TCC、Saga、XA 四大事務(wù)模式的版圖,基本滿足了所有場景分布式事務(wù)處理的需求。
其中XA和AT是無業(yè)務(wù)侵入的,而TCC和Saga是有一定業(yè)務(wù)侵入的。
Seata-AT模式
先來介紹一下AT模式,AT模式是一種沒有侵入的分布式事務(wù)的解決方案,在AT模式下,用戶只需關(guān)注自己的業(yè)務(wù)SQL,用戶的業(yè)務(wù)SQL作為一階段,Seata框架會自動生成事務(wù)進行二階段提交和回滾操作。
兩階段提交協(xié)議的演變:
- 一階段:業(yè)務(wù)數(shù)據(jù)和回滾日志記錄在同一個本地事務(wù)中提交,釋放本地鎖和連接資源。
- 二階段:
提交異步化,非常快速地完成。
回滾通過一階段的回滾日志進行反向補償。
AT模式主要特點
- 最終一致性。
- 性能較XA高。
- 只在第一階段獲取鎖,在第一階段進行提交后釋放鎖。
在一階段中,Seata會攔截 業(yè)務(wù)SQL ,首先解析SQL語義,找到要操作的業(yè)務(wù)數(shù)據(jù),在數(shù)據(jù)被操作前,保存下來記錄 undo log,然后執(zhí)行 業(yè)務(wù)SQL 更新數(shù)據(jù),更新之后再次保存數(shù)據(jù) redo log,最后生成行鎖,這些操作都在本地數(shù)據(jù)庫事務(wù)內(nèi)完成,這樣保證了一階段的原子性。
相對一階段,二階段比較簡單,負責(zé)整體的回滾和提交,如果之前的一階段中有本地事務(wù)沒有通過,那么就執(zhí)行全局回滾,否在執(zhí)行全局提交,回滾用到的就是一階段記錄的 undo Log ,通過回滾記錄生成反向更新SQL并執(zhí)行,以完成分支的回滾。當然事務(wù)完成后會釋放所有資源和刪除所有日志。
AT流程分為兩階段,主要邏輯全部在第一階段,第二階段主要做回滾或日志清理的工作。流程如下:
從上圖中我們可以看到,訂單服務(wù)中TM向TC申請開啟一個全局事務(wù),一般通過@GlobalTransactional標注開啟,TC會返回一個全局事務(wù)ID(XID),訂單服務(wù)在執(zhí)行本地事務(wù)之前,RM會先向TC注冊一個分支事務(wù), 訂單服務(wù)依次生成undo log 執(zhí)行本地事務(wù),生成redo log 提交本地事務(wù),向TC匯報,事務(wù)執(zhí)行OK。
訂單服務(wù)發(fā)起遠程調(diào)用,將事務(wù)ID傳遞給庫存服務(wù),庫存服務(wù)在執(zhí)行本地事務(wù)之前,先向TC注冊分支事務(wù),庫存服務(wù)同樣生成undo Log和redo Log,向TC匯報,事務(wù)狀態(tài)成功。
如果正常全局提交,TC通知RM一步清理掉本地undo和redo日志,如果存在一個服務(wù)執(zhí)行失敗,那么發(fā)起回滾請求。通過undo log進行回滾。
在這里還會存在一個問題,因為每個事務(wù)從本地提交到通知回滾這段時間里面,可能這條數(shù)據(jù)已經(jīng)被其他事務(wù)進行修改,如果直接用undo log進行回滾,可能會導(dǎo)致數(shù)據(jù)不一致的情況,
這個時候 RM會用 redo log進行驗證,對比數(shù)據(jù)是否一樣,從而得知數(shù)據(jù)是否有別的事務(wù)進行修改過,undo log是用于被修改前的數(shù)據(jù),可以用來回滾,redolog是用于被修改后的數(shù)據(jù),用于回滾校驗。
如果數(shù)據(jù)沒有被其他事務(wù)修改過,可以直接進行回滾,如果是臟數(shù)據(jù),redolog校驗后進行處理。
實戰(zhàn)
了解了AT模型的基本操作,接下來就來實戰(zhàn)操作一下,關(guān)于AT模型具體是如何實現(xiàn)的。首先設(shè)計兩個服務(wù) cloud-alibaba-seata-order 和 cloud-alibaba-seata-stock。
表結(jié)構(gòu)t_order、t_stock和undo_log三張表,項目源碼和表結(jié)構(gòu),加上undo_log表,此表用于數(shù)據(jù)的回滾,文末有鏈接。
cloud-alibaba-seata-order核心代碼如下:
controller:
@RestController
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping("order/create")
@GlobalTransactional //開啟分布式事務(wù)
public String create(){
orderService.create();
return "訂單創(chuàng)建成功!";
}
}
OrderService:
public interface OrderService {
void create();
}StockClient:
@FeignClient(value = "seata-stock")
public interface StockClient {
@GetMapping("/stock/reduce")
String reduce();
}
OrderServiceImpl:
@Service
public class OrderServiceImpl implements OrderService{
@Autowired
private OrderMapper orderMapper;
@Autowired
private StockClient stockClient;
@Override
public void create() {
//扣減庫存
stockClient.reduce();
System.out.println("扣減庫存成功!");
//手工異常 用于回滾庫存信息
int i = 1/0;
System.err.println("異常!");
//創(chuàng)建訂單
orderMapper.createOrder();
System.out.println("創(chuàng)建訂單成功!");
}
}
OrderMapper:
@Mapper
public interface OrderMapper {
@Insert("insert into t_order (order_no,order_num) value (order_no+1,1)")
void createOrder();
}
cloud-alibaba-seata-stock核心代碼如下:
@RestController
public class StockController {
@Autowired
private StockService stockService;
@GetMapping("stock/reduce")
public String reduce(){
stockService.reduce();
return "庫存數(shù)量已扣減:"+ new Date();
}
}
public interface StockService {
void reduce();
}@Service
public class StockServiceImpl implements StockService{
@Autowired
StockMapper stockMapper;
@Override
public void reduce() {
stockMapper.reduce();
}
}
@Mapper
@Repository
public interface StockMapper {
@Update("update t_stock set order_num = order_num - 1 where order_no = 1 ")
void reduce();
}
代碼都比較簡單,我們就不做過多的描述,基本注釋也都有,,首先我們需要將order和stock服務(wù)都跑起來,在之前我們的Nacos和Seata都要啟動起來,這個時候我們訪問order的Rest接口,http://localhost:8087/order/create,為了驗證undo_log的表是用于存儲回滾數(shù)據(jù),我們在OrderServiceImpl.create()中添加斷點,用debug的方式啟動。
然后訪問http://localhost:8087/order/create,當程序卡在這個節(jié)點的時間,我們?nèi)タ磚ndo_log和庫存表,會發(fā)現(xiàn),庫存確實減少了,而且undo_log也出現(xiàn)了對應(yīng)的快照記錄修改當前的數(shù)據(jù)信息,這個數(shù)據(jù)就是用來回滾的數(shù)據(jù)。
但是當我們F9通過以后,庫存數(shù)量恢復(fù),并且undo_log表的數(shù)據(jù)行也沒有了,這個時候證明我們的Seata事務(wù)生效,回滾成功。
到這里我們就驗證了AT事務(wù)的執(zhí)行過程,相比于XA和TCC等事務(wù)模型,Seata的AT模型可以應(yīng)對大多數(shù)的業(yè)務(wù)場景,并且可以做到無業(yè)務(wù)侵入,開發(fā)者無感知,對于整個事務(wù)的協(xié)調(diào)、提交或者回滾操作,都可以通過AOP完成,開發(fā)者只需要關(guān)注業(yè)務(wù)即可。
由于Seata需要在不同的服務(wù)之間傳遞全局唯一的事務(wù)ID,和Dubbo等框架集成會比較友好,例如Dubbo可以用過隱士傳參來進行事務(wù)ID的傳遞,整個事務(wù)ID的傳播過程對開發(fā)者也可以做到無感知。
Seata-TCC模式
具體使用案例:https://seata.io/zh-cn/blog/integrate-seata-tcc-mode-with-spring-cloud.html。
什么是TCC
TCC 是分布式事務(wù)中的二階段提交協(xié)議,它的全稱為 Try-Confirm-Cancel,即資源預(yù)留(Try)、確認操作(Confirm)、取消操作(Cancel),他們的具體含義如下:
- Try:對業(yè)務(wù)資源的檢查并預(yù)留。
- Confirm:對業(yè)務(wù)處理進行提交,即 commit 操作,只要 Try 成功,那么該步驟一定成功。
- Cancel:對業(yè)務(wù)處理進行取消,即回滾操作,該步驟回對 Try 預(yù)留的資源進行釋放。
TCC 是一種侵入式的分布式事務(wù)解決方案,以上三個操作都需要業(yè)務(wù)系統(tǒng)自行實現(xiàn),對業(yè)務(wù)系統(tǒng)有著非常大的入侵性,設(shè)計相對復(fù)雜,但優(yōu)點是 TCC 完全不依賴數(shù)據(jù)庫,能夠?qū)崿F(xiàn)跨數(shù)據(jù)庫、跨應(yīng)用資源管理,對這些不同數(shù)據(jù)訪問通過侵入式的編碼方式實現(xiàn)一個原子操作,更好地解決了在各種復(fù)雜業(yè)務(wù)場景下的分布式事務(wù)問題。
TCC和AT區(qū)別
AT 模式基于 支持本地 ACID 事務(wù) 的 關(guān)系型數(shù)據(jù)庫:
- 一階段 prepare 行為:在本地事務(wù)中,一并提交業(yè)務(wù)數(shù)據(jù)更新和相應(yīng)回滾日志記錄。
- 二階段 commit 行為:馬上成功結(jié)束,自動異步批量清理回滾日志。
- 二階段 rollback 行為:通過回滾日志,自動生成補償操作,完成數(shù)據(jù)回滾。
相應(yīng)的,TCC 模式,不依賴于底層數(shù)據(jù)資源的事務(wù)支持:
- 一階段 prepare 行為:調(diào)用自定義的 prepare 邏輯。
- 二階段 commit 行為:調(diào)用自定義的 commit 邏輯。
- 二階段 rollback 行為:調(diào)用自定義的 rollback 邏輯。
所謂 TCC 模式,是指支持把 自定義 的分支事務(wù)納入到全局事務(wù)的管理中。
特點:
- 侵入性比較強,并且需要自己實現(xiàn)相關(guān)事務(wù)控制邏輯
- 在整個過程基本沒有鎖,性能較強
Seata-Saga模式
Saga模式是SEATA提供的長事務(wù)解決方案,在Saga模式中,業(yè)務(wù)流程中每個參與者都提交本地事務(wù),當出現(xiàn)某一個參與者失敗則補償前面已經(jīng)成功的參與者,一階段正向服務(wù)和二階段補償服務(wù)(執(zhí)行處理時候出錯了,給一個修復(fù)的機會)都由業(yè)務(wù)開發(fā)實現(xiàn)。
Saga 模式下分布式事務(wù)通常是由事件驅(qū)動的,各個參與者之間是異步執(zhí)行的,Saga 模式是一種長事務(wù)解決方案。
之前我們學(xué)習(xí)的Seata分布式三種操作模型中所使用的的微服務(wù)全部可以根據(jù)開發(fā)者的需求進行修改,但是在一些特殊環(huán)境下,比如老系統(tǒng),封閉的系統(tǒng)(無法修改,同時沒有任何分布式事務(wù)引入),那么AT、XA、TCC模型將全部不能使用,為了解決這樣的問題,才引用了Saga模型。
比如:事務(wù)參與者可能是其他公司的服務(wù)或者是遺留系統(tǒng),無法改造,可以使用Saga模式。
Saga模式是Seata提供的長事務(wù)解決方案,提供了異構(gòu)系統(tǒng)的事務(wù)統(tǒng)一處理模型。在Saga模式中,所有的子業(yè)務(wù)都不在直接參與整體事務(wù)的處理(只負責(zé)本地事務(wù)的處理),而是全部交由了最終調(diào)用端來負責(zé)實現(xiàn),而在進行總業(yè)務(wù)邏輯處理時,在某一個子業(yè)務(wù)出現(xiàn)問題時,則自動補償全面已經(jīng)成功的其他參與者,這樣一階段的正向服務(wù)調(diào)用和二階段的服務(wù)補償處理全部由總業(yè)務(wù)開發(fā)實現(xiàn)。
Saga狀態(tài)機
目前Seata提供的Saga模式只能通過狀態(tài)機引擎來實現(xiàn),需要開發(fā)者手工的進行Saga業(yè)務(wù)流程繪制,并且將其轉(zhuǎn)換為Json配置文件,而后在程序運行時,將依據(jù)子配置文件實現(xiàn)業(yè)務(wù)處理以及服務(wù)補償處理,而要想進行Saga狀態(tài)圖的繪制,一般需要通過Saga狀態(tài)機來實現(xiàn)。
基本原理:
- 通過狀態(tài)圖來定義服務(wù)調(diào)用的流程并生成json定義文件。
- 狀態(tài)圖中一個節(jié)點可以調(diào)用一個服務(wù),節(jié)點可以配置它的補償節(jié)點。
- 狀態(tài)圖 json 由狀態(tài)機引擎驅(qū)動執(zhí)行,當出現(xiàn)異常時狀態(tài)引擎反向執(zhí)行已成功節(jié)點對應(yīng)的補償節(jié)點將事務(wù)回滾。
- 可以實現(xiàn)服務(wù)編排需求,支持單項選擇、并發(fā)、子流程、參數(shù)轉(zhuǎn)換、參數(shù)映射、服務(wù)執(zhí)行狀態(tài)判斷、異常捕獲等功能。
Saga狀態(tài)機的應(yīng)用
官方文檔地址:https://seata.io/zh-cn/docs/user/saga.html。
Seata Safa狀態(tài)機可視化圖形設(shè)計器使用地址:https://github.com/seata/seata/blob/develop/saga/seata-saga-statemachine-designer/README.zh-CN.md。
總結(jié)
總的來說在Seata的中AT模式基本可以滿足百分之80的分布式事務(wù)的業(yè)務(wù)需求,AT模式實現(xiàn)的是最終一致性,所以可能存在中間狀態(tài),而XA模式實現(xiàn)的強一致性,所以效率較低一點,而Saga可以用來處理不同開發(fā)語言之間的分布式事務(wù),所以關(guān)于分布式事務(wù)的四大模型,基本可以滿足所有的業(yè)務(wù)場景,其中XA和AT沒有業(yè)務(wù)侵入性,而Saga和TCC具有一定的業(yè)務(wù)侵入。
分享文章:分布式事務(wù)(Seata)四大模式詳解
轉(zhuǎn)載注明:http://m.fisionsoft.com.cn/article/cdiieeg.html


咨詢
建站咨詢
