seata 簡介
Seata 是 阿裡巴巴2019年開源的分布式事務解決方案,緻力于在微服務架構下提供高性能和簡單易用的分布式事務服務。在 Seata 開源之前,Seata 對應的内部版本在阿裡内部一直扮演着分布式一緻性中間件的角色,幫助阿裡度過曆年的雙11,對各業務進行了有力的支撐。經過多年沉澱與積累,2019.1 Seata 正式宣布對外開源 。目前 Seata 1.0 已經 GA。
微服務中的分布式事務問題
讓我們想象一下傳統的單片應用程式,它的業務由3個子產品組成,他們使用單個本地資料源。自然,本地事務将保證資料的一緻性。

微服務架構已發生了變化。上面提到的3個子產品被設計為3種服務。本地事務自然可以保證每個服務中的資料一緻性。但是整個業務邏輯範圍如何?
Seata怎麼辦?
我們說,分布式事務是由一批分支事務組成的全局事務,通常分支事務隻是本地事務。
Seata有3個基本組成部分:
- 事務協調器(TC):維護全局事務和分支事務的狀态,驅動全局送出或復原。
- 事務管理器TM:定義全局事務的範圍:開始全局事務,送出或復原全局事務。
- 資料總管(RM):管理正在處理的分支事務的資源,與TC對話以注冊分支事務并報告分支事務的狀态,并驅動分支事務的送出或復原。
Seata管理的分布式事務的典型生命周期:
- TM要求TC開始一項新的全局事務。TC生成代表全局事務的XID。
- XID通過微服務的調用鍊傳播。
- RM将本地事務注冊為XID到TC的相應全局事務的分支。
- TM要求TC送出或回退相應的XID全局事務。
- TC驅動XID的相應全局事務下的所有分支事務以完成分支送出或復原。
快速開始
用例
使用者購買商品的業務邏輯。整個業務邏輯由3個微服務提供支援: - 倉儲服務:對給定的商品扣除倉儲數量。 - 訂單服務:根據采購需求建立訂單。 - 帳戶服務:從使用者帳戶中扣除餘額。
環境準備
步驟 1:建立資料庫
#
seata AT 模式需要 undo_log 表,另外三張是業務表。
步驟 2: 啟動 Seata Server
Server端存儲模式(store.mode)現有file、db兩種(後續将引入raft),file模式無需改動,直接啟動即可。db模式需要導入用于存儲全局事務回話資訊的三張表。
注:file模式為單機模式,全局事務會話資訊記憶體中讀寫并持久化本地檔案root.data,性能較高; db模式為高可用模式,全局事務會話資訊通過db共享,相應性能差些可以直接通過bash 腳本啟動 Seata Server,也可以通過 Docker 鏡像啟動,但是 Docker 方式目前隻支援使用 file 模式,不支援将 Seata-Server 注冊到 Eureka 或 Nacos 等注冊中心。
通過腳本啟動
在 https://github.com/seata/seata/releases 下載下傳相應版本的 Seata Server,解壓後執行以下指令啟動,這裡使用 file 配置
通過 Docker 啟動
docker run --name seata-server -p 8091:8091 seataio/seata-server:latest
項目介紹
| 項目名 | 位址 | 說明 | | :------: | :------: | :------: | | sbm-account-service | 127.0.0.1:8081 | 賬戶服務 | | sbm-order-service | 127.0.0.1:8082 | 訂單服務 | | sbm-storage-service | 127.0.0.1:8083 | 倉儲服務 | | sbm-business-service | 127.0.0.1:8084 | 主業務 | | seata-server | 172.16.2.101:8091 | seata-server |
核心代碼
為了不讓篇幅太長,這裡隻給出部分代碼,詳細代碼文末會給出源碼位址maven 引入 seata 的依賴 eata-spring-boot-starter
<dependency>
倉儲服務
application.properties
spring.application.name=account-service
server.port=8081
spring.datasource.url=jdbc:mysql://172.16.2.101:3306/db_seata?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
seata.tx-service-group=my_test_tx_group
mybatis.mapper-locations=classpath*:mapper/*Mapper.xml
seata.service.grouplist=172.16.2.101:8091
logging.level.io.seata=info
logging.level.io.seata.samples.account.persistence.AccountMapper=debug
StorageService
public
訂單服務
public
帳戶服務
public
主要業務邏輯
隻需要使用一個 @GlobalTransactional 注解在業務方法上。
@GlobalTransactional
XID 的傳遞
全局事務ID的跨服務傳遞,需要我們自己實作,這裡通過攔截器的方式。每個服務都需要添加下面兩個類。
SeataFilter
@Component
SeataRestTemplateAutoConfiguration
@Configuration
測試
測試成功場景:
curl -X POST http://127.0.0.1:8084/api/business/purchase/commit
此時傳回結果為:true
測試失敗場景:
UserId 為1002 的使用者下單,sbm-account-service會抛出異常,事務會復原
http://127.0.0.1:8084/api/business/purchase/rollback
此時傳回結果為:false
檢視 undo_log 的日志或者主鍵,可以看到在執行過程中有儲存資料。 如檢視主鍵自增的值,在執行前後的值會發生變化,在執行前是 1,執行後是 7 。
源碼位址
https://github.com/gf-huanchupk/SpringBootLearning/tree/master/springboot-seata
參考
http://seata.io/zh-cn/docs/overview/what-is-seata.html