分佈式事務框架 seata
1. 什麼是 seata
Seata 是一款開源的分佈式事務解決方案,致力於提供高性能和簡單易用的分佈式事務服務。Seata 將爲用戶提供了 AT、TCC、SAGA 和 XA 事務模式,爲用戶打造一站式的分佈式解決方案。
2. seata 發展歷程
阿里巴巴作爲國內最早一批進行應用分佈式(微服務化)改造的企業,很早就遇到微服務架構下的分佈式事務問題。阿里巴巴對於分佈式事務問題先後發佈了以下解決方案:
-
2014 年,阿里中間件團隊發佈 TXC(Taobao Transaction Constructor),爲集團內應用提供分佈式事務服務。
-
2016 年,TXC 在經過產品化改造後,以 GTS(Global Transaction Service) 的身份登陸阿里雲,成爲當時業界唯一一款雲上分佈式事務產品。在阿雲裏的公有云、專有云解決方案中,開始服務於衆多外部客戶。
-
2019 年起,基於 TXC 和 GTS 的技術積累,阿里中間件團隊發起了開源項目 Fescar(Fast & EaSy Commit And Rollback, FESCAR),和社區一起建設這個分佈式事務解決方案。
-
2019 年 fescar 被重命名爲了 seata(simple extensiable autonomous transaction architecture)。
-
TXC、GTS、Fescar 以及 seata 一脈相承,爲解決微服務架構下的分佈式事務問題交出了一份與衆不同的答卷。
3. seata 中相關事務概念
-
全局事務:全局事務指的是一次性操作多個資源管理器完成的事務,由一組分支事務(本地事務)組成。
-
分支事務(本地事務):本地事務由本地資源管理器(通常指數據庫管理系統 DBMS,例如 MySQL、Oracle 等)管理,嚴格地支持 ACID 特性,高效可靠。本地事務不具備分佈式事務的處理能力,隔離的最小單位受限於資源管理器,即本地事務只能對自己數據庫的操作進行控制,對於其他數據庫的操作則無能爲力。
4. seata 的工作流程相關概念
Seata 對分佈式事務的協調和控制,主要是通過 XID 和 3 個核心組件實現的。
XID
XID 是全局事務的唯一標識,它可以在服務的調用鏈路中傳遞,綁定到服務的事務上下文中。
核心組件
Seata 的核心組件可分爲 Seata 服務端和 Seata 客戶端兩類
Seata 定義了 3 個核心組件:
-
TC(Transaction Coordinator):事務協調器,直接調度事務參與者 RM。負責將 RM 的反饋結果響應給 TM,並聽從 TM 的最終決議,將具體決議(提交或回滾)發送給 RM 執行。相當於中間人,主要負責維護全局事務和分支事務的狀態。
-
TM(Transaction Manager):事務管理器,它是事務的發起者(具體的微服務)。根據 RM 第一階段的執行結果,進行決議。並將決議反饋給 TC。相當於發號施令的
-
RM(Resource Manager):資源管理器,其實就是事務的參與者。獲取 TC 的執行命令具去執行分支事務的第一階段以及第二階段,並將執行結果反饋給 TC,相當於具體做事的
以上三個組件相互協作,TC 以 Seata 服務器(Server)形式獨立部署,TM 和 RM 則是以 Seata Client 的形式集成在微服務中運行。
5. seata 的工作流程
TC 以 Seata 服務器(Server)形式獨立部署,TM 和 RM 則是以 Seata Client 的形式集成在微服務中運行,
整體工作流程如圖:
Seata 的整體工作流程如下:
-
TM 向 TC 申請開啓一個全局事務,全局事務創建成功後,TC 會針對這個全局事務生成一個全局唯一的 XID(此時,由 TM 發起的全局事務已經開啓)
-
XID 通過服務的調用鏈傳遞到其他服務
-
RM 向 TC 註冊一個分支事務,並將其納入 XID 對應全局事務的管轄(事務參與者執行本地事務,此時分支事務已經執行完成,並反饋給 TC 執行結果。可以理解爲 AT 模式下的第一個階段)
-
TM 根據 TC 收集的各個分支事務的執行結果,向 TC 發起全局事務提交或回滾決議(事務協調者根據事務管理者的決議,發送提交或回滾的調度命令,可以理解爲 AT 模式下的第二階段)
-
TC 調度 XID 下管轄的所有分支事務完成提交或回滾操作
6. seata 的 AT 模式
seata 中提供了了 XA、TCC、SAGA、TC 四種模式。其中 TC 模式應用最爲廣泛,可應對大多數業務場景。也是 seata 的主要模式
前提
-
基於支持本地 ACID 事務的關係型數據庫。例如 mysql,oracle
-
Java 應用,通過 JDBC 訪問數據庫。(mybaits、mybatisplus、springdatajpa)
整體機制
官網描述:
兩階段提交協議的演變:
-
一階段:業務數據和回滾日誌記錄在同一個本地事務中提交(提交前需要獲取到全局鎖),釋放本地鎖和連接資源。
-
二階段:
提交異步化,非常快速地完成。
回滾通過一階段的回滾日誌進行反向補償。
其實 AT 模式可以理解爲 XA 二階段提交的一個變種,將二階段提交的部分在一定階段就已完成,而二階段的回滾操作是通過回滾日誌完成,並是不依賴於數據庫的事務機制。也就是說一階段數據實際上已經提交了,與此同時原子性提交的還有對應的回滾日誌
寫隔離
-
一階段本地事務提交前,需要確保先拿到 全局鎖 。
-
拿不到 全局鎖 ,不能提交本地事務。
-
拿 全局鎖 的嘗試被限制在一定範圍內,超出範圍將放棄,並回滾本地事務,釋放本地鎖。此時一階段等於失敗
讀隔離
在數據庫本地事務隔離級別 讀已提交(Read Committed) 或以上的基礎上,Seata(AT 模式)的默認全局隔離級別是 讀未提交(Read Uncommitted) 。
如果應用在特定場景下,必需要求全局的 讀已提交 ,目前 Seata 的方式是通過 SELECT FOR UPDATE 語句的代理。
7. seata 的 AT 模式具體執行流程
假設前置條件
假設當前存在一個業務表:product
分支事務的業務邏輯:
update product set name = 'GTS' where name = 'TXC';
一階段
-
解析 SQL:得到 SQL 的類型(UPDATE),表(product),條件(where name = 'TXC')等相關的信息。
-
查詢前鏡像:根據解析得到的條件信息,生成查詢語句,定位數據。這一步的目的爲了後續回滾
select id, name, since from product where name = 'TXC';
-
執行業務 SQL:更新這條記錄的 name 爲'GTS'。
-
查詢後鏡像:根據主鍵 ID 進行查詢。這一步的目的是爲了防止存在其他線程修改數據,後續比對使用
select id, name, since from product where id = 1;
- 插入回滾日誌:把前後鏡像數據以及業務 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 的記錄的 全局鎖 。
-
本地事務提交:業務數據的更新和前面步驟中生成的 UNDO LOG 一併提交。
-
將本地事務提交的結果上報給 TC。
二階段 - 提交
相關業務在一階段已經提交了,二階段只需要刪除已經沒有用處的回滾日誌即可。同時還是異步刪除,效率更高
-
收到 TC 的提交指令,把請求放入一個異步任務的隊列中,馬上返回提交成功的結果給 TC。
-
異步任務階段將異步和批量地刪除相應 UNDO LOG 記錄。
二階段 - 回滾
相關業務在一階段已經提交了,所以二階段的回滾相當於又開啓了一個事務。一階段保存的後鏡像來用於對比是否有其他動作修改了這條數據,一階段保存的前鏡像用於回滾語句的生成
-
收到 TC 的回滾指令,開啓一個本地事務,執行如下操作。
-
通過 XID 和 Branch ID 查找到相應的 UNDO LOG 記錄。
-
數據校驗:拿 UNDO LOG 中的後鏡像與當前數據進行比較,如果有不同,說明數據被當前全局事務之外的動作做了修改。這種情況,需要根據配置策略來做處理
-
根據 UNDO LOG 中的前鏡像和業務 SQL 的相關信息生成並執行回滾的語句,同時刪除已經無用的回滾日誌
update product set name = 'TXC' where id = 1;
- 提交本地事務。並把本地事務的執行結果(即分支事務補償的結果)上報給 TC。
souce://www.yuque.com/u27809381/ca4o9w/avy27g
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/bUQhtSAS7HeY7RNI1zBY4w