快速瞭解阿里微服務熱門開源分散式事務框架——Seata
阿新 • • 發佈:2020-11-12
### **一、Seata 概述**
`Seata` 是 `Simple Extensible Autonomous Transaction Architecture` 的簡寫,由 `feascar` 改名而來。
Seata 是阿里開源的分散式事務框架,屬於二階段提交模式。
目前github上已經有 `12267` 顆星了,也很活躍,最新的提交時間很多都是幾天前。
首先我們回顧一下在單體應用中,例如一個業務呼叫了3個模組,他們都使用同一個資料來源,是靠本地事務來保證事務一致性。
![](https://upload-images.jianshu.io/upload_images/15462057-565f124d35cc6f00?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
但在微服務架構中,這3個模組會變為3個獨立的微服務,各自有自己的資料來源,呼叫邏輯就變為:
![](https://upload-images.jianshu.io/upload_images/15462057-4d6da311890c8215?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
### **Seata 如何處理呢?**
![](https://upload-images.jianshu.io/upload_images/15462057-4d585a9ed400e81a?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
Business 是業務入口,在程式中會通過**註解**來說明他是一個**全域性事務**,這時他的角色為 TM(事務管理者)。
Business 會請求 TC(事務協調器,一個獨立執行的服務),說明自己要開啟一個全域性事務,TC 會生成一個全域性事務ID(XID),並返回給 Business。
Business 得到 XID 後,開始呼叫微服務,例如呼叫 Storage。
![](https://upload-images.jianshu.io/upload_images/15462057-e1c3b4fed2b499fa?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
(*和上面的圖一樣,方便檢視,防止滾到到這兒時已經看不到上面的圖片了*)
Storage 會收到 XID,知道自己的事務屬於這個全域性事務。Storage 執行自己的業務邏輯,操作本地資料庫。
Storage 會把自己的事務註冊到 TC,作為這個 XID 下面的一個**分支事務**,並且把自己的事務執行結果也告訴 TC。
此時 Storage 的角色是 RM(資源管理者),資源是指本地資料庫。
Order、Account 的執行邏輯與 Storage 一致。
在各個微服務都執行完成後,TC 可以知道 XID 下各個分支事務的執行結果,TM(Business) 也就知道了。
Business 如果發現各個微服務的本地事務都執行成功了,就請求 TC 對這個 XID 提交,否則回滾。
TC 收到請求後,向 XID 下的所有分支事務發起相應請求。
各個微服務收到 TC 的請求後,執行相應指令,並把執行結果上報 TC。
### **重要機制**
(1)全域性事務的回滾是如何實現的呢?
Seata 有一個重要的機制:**回滾日誌**。
每個分支事務對應的資料庫中都需要有一個`回滾日誌表 UNDO_LOG`,在真正修改資料庫記錄之前,都會先記錄修改前的記錄值,以便之後回滾。
在收到回滾請求後,就會根據 `UNDO_LOG` 生成回滾操作的 SQL 語句來執行。
如果收到的是提交請求,就把 `UNDO_LOG` 中的相應記錄刪除掉。
(2)RM 是怎麼自動和 TC 互動的?
是通過**監控攔截JDBC**實現的,例如監控到開啟本地事務了,就會自動向 TC 註冊、生成回滾日誌、向 TC 彙報執行結果。
(3)二階段回滾失敗怎麼辦?
例如 TC 命令各個 RM 回滾的時候,有一個微服務掛掉了,那麼所有正常的微服務也都不會執行回滾,當這個微服務重新正常執行後,TC 會重新執行全域性回滾。
**1.3 核心元件**
回顧一下其中的**核心元件**:
* 事務協調器 TC
維護全域性和分支事務的狀態,指示全域性提交或者回滾。
* 事務管理者 TM
開啟、提交或者回滾一個全域性事務。
* 資源管理者 RM
管理執行分支事務的那些資源,向TC註冊分支事務、上報分支事務狀態、控制分支事務的提交或者回滾。
**1.4 具體工作過程**
再從巨集觀上梳理一下 Seata 的工作過程:
![](https://upload-images.jianshu.io/upload_images/15462057-700402713fb40bff?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
* TM 請求 TC,開始一個新的全域性事務,TC 會為這個全域性事務生成一個 XID。
* XID 通過微服務的呼叫鏈傳遞到其他微服務。
* RM 把本地事務作為這個XID的分支事務註冊到TC。
* TM 請求 TC 對這個 XID 進行提交或回滾。
* TC 指揮這個 XID 下面的所有分支事務進行提交、回滾。
### **二、Seata 詳細工作流程示例**
下面我們通過一個分支事務的執行過程來了解 Seata 的工作流程。
例如有一個業務表 `product(id,name)`,分支事務的業務邏輯:
```
update product set name = 'GTS' where name = 'TXC';
```
**2.1 一階段**
(1)解析 SQL
得到 SQL 的型別(UPDATE),表(product),條件(where name = 'TXC')等相關的資訊。
(2)查詢前映象
根據解析得到的條件資訊,生成查詢語句,定位資料。
```
select id, name from product where name = 'TXC';
```
得到前映象:
| id | name |
| --- | --- |
| 1 | TXC |
(3)執行業務 SQL
執行自己的業務邏輯:
```
update product set name = 'GTS' where name = 'TXC';
```
把 `name` 改為了 `GTS`。
(4)查詢後鏡像
根據前映象的結果,通過 主鍵 定位資料。
```
select id, name from product where id = 1;
```
得到後鏡像:
| id | name |
| --- | --- |
| 1 | GTS |
(5)插入回滾日誌
把前後映象資料以及業務 SQL 相關的資訊組成一條回滾日誌記錄,插入到 `UNDO_LOG` 表中。
(6)提交前,向 TC 註冊分支:申請 `product` 表中,主鍵值等於 1 的記錄的 全域性鎖 。
(7)本地事務提交:業務資料的更新和前面步驟中生成的 UNDO LOG 一併提交。
(8)將本地事務提交的結果上報給 TC。
**2.2 二階段 - 回滾**
(1)收到 TC 的分支回滾請求,開啟一個本地事務,執行如下操作。
(2)通過 XID 和 Branch ID 查詢到相應的 UNDO LOG 記錄。
(3)資料校驗
拿 UNDO LOG 中的後鏡與當前資料進行比較,根據校驗結果決定是否做回滾。
(4)根據 UNDO LOG 中的前映象和業務 SQL 的相關資訊生成並執行回滾的語句:
```
update product set name = 'TXC' where id = 1;
```
(5)提交本地事務
並把本地事務的執行結果(即分支事務回滾的結果)上報給 TC。
**二階段 - 提交**
(1)收到 TC 的分支提交請求,把請求放入一個非同步任務的佇列中,馬上返回提交成功的結果給 TC。
(2)非同步任務階段的分支提交請求,將非同步和批量地刪除相應 UNDO LOG 記錄。
### **三、小結**
上面介紹的是 Seata 的 `AT 模式`,就是自動化事務,使用非常簡單,對業務程式碼沒有侵入性。
不足的地方是目前文件比較少,網上的相關材料也不是很多,所以使用過程中遇到問題時可能就需要自己檢視原始碼,分析原理。
Seata 還支援 TCC 和 Saga 模式,但支援的主要方式是 AT。
### **寫在最後**
歡迎大家關注我的公眾號【**風平浪靜如碼**】,海量Java相關文章,學習資料都會在裡面更新,整理的資料也會放在裡面。
覺得寫的還不錯的就點個贊,加個關注唄!點關注,不迷路,持續更新