1. 程式人生 > >快速瞭解阿里微服務熱門開源分散式事務框架——Seata

快速瞭解阿里微服務熱門開源分散式事務框架——Seata

### **一、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相關文章,學習資料都會在裡面更新,整理的資料也會放在裡面。 覺得寫的還不錯的就點個贊,加個關注唄!點關注,不迷路,持續更新