Seata 是什么
Seata 是一款開源的分布式事務解決方案谷丸,致力于提供高性能和簡單易用的分布式事務服務。Seata 將為用戶提供了 AT应结、TCC刨疼、SAGA 和 XA 事務模式,為用戶打造一站式的分布式解決方案鹅龄。
什么是分布式事務問題
-
單體應用
單體應用中揩慕,一個業(yè)務操作需要調用三個模塊完成,此時數據的一致性由本地事務來保證扮休。
單體應用單一數據庫使用本地事務 -
微服務應用
隨著業(yè)務需求的變化迎卤,單體應用被拆分成微服務應用,原來的三個模塊被拆分成三個獨立的應用玷坠,分別使用獨立的數據源止吐,業(yè)務操作需要調用三個服務來完成。此時每個服務內部的數據一致性由本地事務來保證侨糟,但是全局的數據一致性問題沒法保證碍扔。
微服務多數據源
總結:
在微服務架構中由于全局數據一致性沒法保證產生的問題就是分布式事務問題。簡單來說秕重,一次業(yè)務操作需要操作多個數據源或需要進行遠程調用不同,就會產生分布式事務問題。
分布式事務處理過程的三個組件
Transaction Coordinator (TC): 事務協調器溶耘,維護全局事務的運行狀態(tài)二拐,負責協調并驅動全局事務的提交或回滾;可以理解為Seata凳兵。
Transaction Manager (TM): 控制全局事務的邊界百新,負責開啟一個全局事務,并最終發(fā)起全局提交或全局回滾的決議庐扫;可以理解為@GlobalTransaction注解饭望。
Resource Manager (RM): 控制分支事務,負責分支注冊形庭、狀態(tài)匯報铅辞,并接收事務協調器的指令,驅動分支(本地)事務的提交和回滾萨醒≌迳海可以理解為MySQL數據庫。
分布式事務執(zhí)行過程
- TM 向 TC 申請開啟一個全局事務富纸,全局事務創(chuàng)建成功并生成一個全局唯一的 XID囤踩;
- XID 在微服務調用鏈路的上下文中傳播旨椒;
- RM 向 TC 注冊分支事務,將其納入 XID 對應全局事務的管轄堵漱;
- TM 向 TC 發(fā)起針對 XID 的全局提交或回滾決議综慎;
-
TC 調度 XID 下管轄的全部分支事務完成提交或回滾請求。分布式事務執(zhí)行過程
四種事務模式
Seata 目標打造一站式的分布事務的解決方案怔锌,最終會提供四種事務模式:
- AT 模式:參見《Seata AT 模式》文檔
- TCC 模式:參見《Seata TCC 模式》文檔
- Saga 模式:參見《SEATA Saga 模式》文檔
- XA 模式:正在開發(fā)中...
目前使用的流行度情況是:AT > TCC > Saga寥粹。因此,我們在學習 Seata 的時候埃元,可以花更多精力在 AT 模式上涝涤,最好搞懂背后的實現原理,畢竟分布式事務涉及到數據的正確性岛杀,出問題需要快速排查定位并解決阔拳。
AT 模式
前提
- 基于支持本地 ACID 事務的關系型數據庫。
- Java 應用类嗤,通過 JDBC 訪問數據庫糊肠。
整體機制
- 一階段:業(yè)務數據和回滾日志記錄在同一個本地事務中提交,釋放本地鎖和連接資源遗锣。
- 二階段:
提交異步化货裹,非常快速地完成精偿。
回滾通過一階段的回滾日志進行反向補償弧圆。
工作機制
以一個示例來說明整個 AT 分支的工作過程。
業(yè)務表:product
Field | Type | Key |
---|---|---|
id | bigint(20) | PRI |
name | varchar(100) | |
since | varchar(100) |
AT 分支事務的業(yè)務邏輯:
update product set name = 'GTS' where name = 'TXC';
一階段
過程:
- 解析 SQL:得到 SQL 的類型(UPDATE)笔咽,表(product)搔预,條件(where name = 'TXC')等相關的信息。
- 查詢前鏡像:根據解析得到的條件信息叶组,生成查詢語句拯田,定位數據。
select id, name, since from product where name = 'TXC';
- 得到前鏡像:
id | name | since |
---|---|---|
1 | TXC | 2014 |
- 執(zhí)行業(yè)務 SQL:更新這條記錄的 name 為 'GTS'甩十。
- 查詢后鏡像:根據前鏡像的結果船庇,通過主鍵定位數據。
select id, name, since from product where id = 1
;` - 得到后鏡像:
id | name | since |
---|---|---|
1 | GTS | 2014 |
- 插入回滾日志:把前后鏡像數據以及業(yè)務 SQL 相關的信息組成一條回滾日志記錄枣氧,插入到 UNDO_LOG 表中溢十。
{
"branchId": 641789253,
"undoItems": [{
"afterImage": {
"rows": [{
"fields": [{
"name": "id",
"type": 4,
"value": 1
}, {
"name": "name",
"type": 12,
"value": "GTS"
}, {
"name": "since",
"type": 12,
"value": "2014"
}]
}],
"tableName": "product"
},
"beforeImage": {
"rows": [{
"fields": [{
"name": "id",
"type": 4,
"value": 1
}, {
"name": "name",
"type": 12,
"value": "TXC"
}, {
"name": "since",
"type": 12,
"value": "2014"
}]
}],
"tableName": "product"
},
"sqlType": "UPDATE"
}],
"xid": "xid:xxx"
}
- 提交前,向 TC 注冊分支:申請 product 表中达吞,主鍵值等于 1 的記錄的 全局鎖 。
- 本地事務提交:業(yè)務數據的更新和前面步驟中生成的 UNDO LOG 一并提交荒典。
- 將本地事務提交的結果上報給 TC酪劫。
二階段-回滾
- 收到 TC 的分支回滾請求吞鸭,開啟一個本地事務,執(zhí)行如下操作覆糟。
- 通過 XID 和 Branch ID 查找到相應的 UNDO LOG 記錄刻剥。
- 數據校驗:拿 UNDO LOG 中的后鏡與當前數據進行比較,如果有不同滩字,說明數據被當前全局事務之外的動作做了修改造虏。這種情況,需要根據配置策略來做處理麦箍,詳細的說明在另外的文檔中介紹漓藕。
- 根據 UNDO LOG 中的前鏡像和業(yè)務 SQL 的相關信息生成并執(zhí)行回滾的語句:
update product set name = 'TXC' where id = 1;
- 提交本地事務。并把本地事務的執(zhí)行結果(即分支事務回滾的結果)上報給 TC挟裂。
二階段-提交
- 收到 TC 的分支提交請求享钞,把請求放入一個異步任務的隊列中,馬上返回提交成功的結果給 TC诀蓉。
- 異步任務階段的分支提交請求將異步和批量地刪除相應 UNDO LOG 記錄栗竖。