1. 程式人生 > 其它 >Album++:分散式事務專輯- Seata 解決方案

Album++:分散式事務專輯- Seata 解決方案

Seata 解決方案:↓ ↓ ↓

Seata是由阿里中介軟體團隊發起的開源專案 Fescar,後更名為Seata,它是一個是開源的分散式事務框架。

傳統2PC的問題在Seata中得到了解決,它通過對本地關係資料庫的分支事務的協調來驅動完成全域性事務,是工作 在應用層的中介軟體。

主要優點是效能較好,且不長時間佔用連線資源,它以高效並且對業務0侵入的方式解決微服 務場景下面臨的分散式事務問題,它目前提供AT模式(即2PC)及TCC模式的分散式事務解決方案。

Seata的設計思想如下:

Seata的設計目標其一是對業務無侵入,因此從業務無侵入的2PC方案著手,在傳統2PC的基礎上演進,並解決 2PC方案面臨的問題。

Seata把一個分散式事務理解成一個包含了若干分支事務的全域性事務。

全域性事務的職責是協調其下管轄的分支事務 達成一致,要麼一起成功提交,要麼一起失敗回滾。

此外,通常分支事務本身就是一個關係資料庫的本地事務,

下圖是全域性事務與分支事務的關係圖↓ ↓ ↓

與 傳統2PC 的模型類似,Seata定義了3個元件來協議分散式事務的處理過程:↓ ↓ ↓

Transaction Coordinator (TC): 事務協調器,它是獨立的中介軟體,需要獨立部署執行,它維護全域性事務的運 行狀態,接收TM指令發起全域性事務的提交與回滾,負責與RM通訊協調各各分支事務的提交或回滾。

Transaction Manager (TM): 事務管理器,TM需要嵌入應用程式中工作,它負責開啟一個全域性事務,並最終 向TC發起全域性提交或全域性回滾的指令。

Resource Manager (RM): 控制分支事務,負責分支註冊、狀態彙報,並接收事務協調器TC的指令,驅動分 支(本地)事務的提交和回滾。

還拿新使用者註冊送積分舉例Seata的分散式事務過程↓ ↓ ↓

具體的執行流程如下:

1. 使用者服務的 TM 向 TC 申請開啟一個全域性事務,全域性事務建立成功並生成一個全域性唯一的XID。

2. 使用者服務的 RM 向 TC 註冊 分支事務,該分支事務在使用者服務執行新增使用者邏輯,並將其納入 XID 對應全域性 事務的管轄。

3. 使用者服務執行分支事務,向用戶表插入一條記錄。

4. 邏輯執行到遠端呼叫積分服務時(XID 在微服務呼叫鏈路的上下文中傳播)。積分服務的RM 向 TC 註冊分支事 務,該分支事務執行增加積分的邏輯,並將其納入 XID 對應全域性事務的管轄。

5. 積分服務執行分支事務,向積分記錄表插入一條記錄,執行完畢後,返回使用者服務。

6. 使用者服務分支事務執行完畢。

7. TM 向 TC 發起針對 XID 的全域性提交或回滾決議。

8. TC 排程 XID 下管轄的全部分支事務完成提交或回滾請求。

Seata 實現 2PC 與傳統2PC的差別:

架構層次方面,傳統2PC方案的 RM 實際上是在資料庫層,RM 本質上就是資料庫自身,通過 XA 協議實現,而 Seata的 RM 是以jar包的形式作為中介軟體層部署在應用程式這一側的。

兩階段提交方面,傳統2PC無論第二階段的決議是commit還是rollback,事務性資源的鎖都要保持到Phase2完成 才釋放。

而Seata的做法是在Phase1 就將本地事務提交,這樣就可以省去Phase2持鎖的時間,整體提高效率。

seata實現 2PC 事務↓ ↓ ↓

業務說明:

  本示例通過Seata中介軟體實現分散式事務,模擬三個賬戶的轉賬交易過程。

兩個賬戶在三個不同的銀行(張三在bank1、李四在bank2),bank1和bank2是兩個個微服務。

交易過程是,張三 給李四轉賬指定金額。 上述交易步驟,要麼一起成功,要麼一起失敗,必須是一個整體性的事務。

程式組成部分

本示例程式組成部分如下:

   資料庫:MySQL-5.7.25 包括bank1和bank2兩個資料庫。

  JDK:64位jdk1.8.0_201

  微服務框架:spring-boot-2.1.3、spring-cloud-Greenwich.RELEASE

  seata客戶端(RM、TM):spring-cloud-alibaba-seata-2.1.0.RELEASE

  seata服務端(TC):seata-server-0.7.1

  微服務及資料庫的關係:

    dtx/dtx-seata-demo/seata-demo-bank1銀行1,操作張三賬戶,連線資料庫bank1

    dtx/dtx-seata-demo/seata-demo-bank2銀行2,操作李四賬戶,連線資料庫bank2

  服務註冊中心:dtx/discover-server

下載seata伺服器:https://github.com/seata/seata/releases/download/v0.7.1/seata-server-0.7.1.zip
啟動方式: /bin/seata-server.bat-p8888-mfile
注:其中8888為服務埠號;file為啟動模式,這裡指seata服務將採用檔案的方式儲存資訊。

本示例程式技術架構如下:

互動流程如下:

1、請求bank1進行轉賬,傳入轉賬金額。

2、bank1減少轉賬金額,呼叫bank2,傳入轉賬金額。

傳送門 >>> 資料下載

建立資料庫 匯入資料庫指令碼:

bank1.sql、bank2.sql

包括如下資料庫:↓↓↓

bank1 庫,包含張三賬戶

CREATE DATABASE `bank1` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
DROP TABLE IF EXISTS `account_info`; 
CREATE TABLE `account_info` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `account_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '戶 主姓名', `account_no` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '銀行 卡號', `account_password` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '帳戶密碼', `account_balance` double NULL DEFAULT NULL COMMENT '帳戶餘額', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic; INSERT INTO `account_info` VALUES (2, '張三的賬戶', '1', '', 10000);

bank2庫,包含李四賬戶

CREATE DATABASE `bank2` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
CREATE TABLE `account_info` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `account_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '戶 主姓名', `account_no` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '銀行 卡號', `account_password` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '帳戶密碼', `account_balance` double NULL DEFAULT NULL COMMENT '帳戶餘額', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic; INSERT INTO `account_info` VALUES (3, '李四的賬戶', '2', NULL, 0);

分別在bank1、bank2庫中建立undo_log表,此表為seata框架使用:

CREATE TABLE `undo_log` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `branch_id` bigint(20) NOT NULL, `xid` varchar(100) NOT NULL, `context` varchar(128) NOT NULL, `rollback_info` longblob NOT NULL, `log_status` int(11) NOT NULL, `log_created` datetime NOT NULL, `log_modified` datetime NOT NULL, `ext` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

啟動TC(事務協調器):下載方式 ↑

如上圖出現“Server started...”的字樣則表示啟動成功。

discover-server:

discover-server是服務註冊中心,測試工程將自己註冊至discover-server。

discover-server基於Eureka實現。

匯入案例工程 dtx-seata-demo

dtx-seata-demo是seata的測試工程,根據業務需求需要建立兩個dtx-seata-demo工程。

(1)匯入dtx-seata-demo 匯入:資料\基礎程式碼\dtx-seata-demo到父工程dtx下。

兩個測試工程如下:

dtx/dtx-seata-demo/dtx-seata-demo-bank1 ,操作張三賬戶,連線資料庫bank1

dtx/dtx-seata-demo/dtx-seata-demo-bank2 ,操作李四賬戶,連線資料庫bank2

父工程maven依賴說明:

在dtx父工程中指定了SpringBoot和SpringCloud版本

在dtx-seata-demo父工程中指定了spring-cloud-alibaba-dependencies的版本

配置seata

在src/main/resource中,新增registry.conf、file.conf檔案,內容可拷貝seata-server-0.7.1中的配置檔案子。

在registry.conf中registry.type 使用 file:

在file.conf中更改service.vgroup_mapping.[springcloud服務名]-fescar-service-group = "default",並修改 service.default.grouplist =[seata服務端地址]

關於vgroup_mapping的配置:

vgroup_mapping.事務分組服務名=Seata Server叢集名稱(預設名稱為default)

default.grouplist = Seata Server叢集地址

在 org.springframework.cloud:spring-cloud-starter-alibaba-seata 的 org.springframework.cloud.alibaba.seata.GlobalTransactionAutoConfiguration 類中,

預設會使用 ${spring.application.name}-fescar-service-group 作為事務分組服務名註冊到 Seata Server上,如果和 file.conf 中的配置不一致,

會提示 no available server to connect 錯誤 也可以通過配置 spring.cloud.alibaba.seata.tx-service-group 修改後綴,但是必須和 file.conf 中的配置保持 一致。

建立代理資料來源 :

新增DatabaseConfiguration.java,Seata的RM通過DataSourceProxy才能在業務程式碼的事務提交時,通過這個切 入點,與TC進行通訊互動、記錄undo_log等。

@Configuration 
public class DatabaseConfiguration { @Bean @ConfigurationProperties(prefix = "spring.datasource.ds0") public DruidDataSource ds0() { DruidDataSource druidDataSource = new DruidDataSource(); return druidDataSource; } @Primary @Bean public DataSource dataSource(DruidDataSource ds0) { DataSourceProxy pds0 = new DataSourceProxy(ds0); return pds0; } }

Seata執行流程:

正常提交流程 ↓↓↓

回滾流程 回滾流程省略前的RM註冊過程↓↓↓

說明:

1、每個RM使用DataSourceProxy連線資料庫,其目的是使用ConnectionProxy,使用資料來源和資料連線代理的目 的就是在第一階段將undo_log和業務資料放在一個本地事務提交,這樣就儲存了只要有業務操作就一定有 undo_log。

2、在第一階段undo_log中存放了資料修改前和修改後的值,為事務回滾作好準備,所以第一階段完成就已經將分 支事務提交,也就釋放了鎖資源。

3、TM開啟全域性事務開始,將XID全域性事務id放在事務上下文中,通過feign呼叫也將XID傳入下游分支事務,每個 分支事務將自己的Branch ID分支事務ID與XID關聯。

4、第二階段全域性事務提交,TC會通知各各分支參與者提交分支事務,在第一階段就已經提交了分支事務,這裡各 各參與者只需要刪除undo_log即可,並且可以非同步執行,第二階段很快可以完成。

5、第二階段全域性事務回滾,TC會通知各各分支參與者回滾分支事務,通過 XID 和 Branch ID 找到相應的回滾日 志,通過回滾日誌生成反向的 SQL 並執行,以完成分支事務回滾到之前的狀態,如果回滾失敗則會重試回滾操 作。

測試場景:

1、張三向李四轉賬成功。

2、李四事務失敗,張三事務回滾成功。

3、張三事務失敗,李四事務回滾成功。

4、分支事務超時測試。

小結

本節講解了傳統2PC(基於資料庫XA協議)和Seata實現2PC的兩種2PC方案,由於Seata的0侵入性並且解決了傳 統2PC長期鎖資源的問題,所以推薦採用Seata實現2PC。

Seata實現2PC要點:

1、全域性事務開始使用 @GlobalTransactional標識 。

2、每個本地事務方案仍然使用@Transactional標識。

3、每個資料都需要建立undo_log表,此表是seata保證本地事務一致性的關鍵

Face your past without regret. Handle your present with confidence.Prepare for future without fear. keep the faith and drop the fear.

面對過去無怨無悔,把握現在充滿信心,備戰未來無所畏懼。保持信念,克服恐懼!一點一滴的積累,一點一滴的沉澱,學技術需要不斷的積澱!