分佈式事務(一)


黑馬-分佈式事務篇事務控制解決方案手敲筆記

一.基礎概念

1.1 什麼是分佈式事務

隨着互聯網的發展,軟件系統也從原來的單體應用變爲分佈式應用。分佈式系統把一個應用系統拆分爲多個獨立部署的服務,每個服務都對應自己的數據庫,每個服務之間通過遠程協作完成業務操作,這種分佈式系統環境下由不同服務之間通過網絡遠程協作完成事務稱爲分佈式事務
在這裏插入圖片描述
例如:用戶訂單減庫存,銀行轉賬等都是分佈式事務的體現。

本地事務:

begin transaction
    //本地數據庫操作 :張三減少金額
    //本地數據庫操作 :李四增加金額
commit transaction

分佈式事務環境下,操作變爲下面這樣:

begin transaction
    //本地數據庫操作 :張三減少金額
    //遠程調用 :李四增加金額
commit transaction

當遠程調用讓李四增加金額成功後,但是由於網絡原因超時沒有返回,此時本地事務提交失敗就回滾了張三減少金額的操作,此時金額就出現了不一致。

因此在分佈式架構的基礎上,傳統數據庫事務就無法使用,張三和李四的賬戶不在同一個數據庫甚至不在同一個應用系統裏,實現轉賬事務需要通過遠程調用,由於網絡原因就會導致分佈式事務問題

1.2 分佈式事務產生的場景
  • 微服務架構

    微服務之間通過遠程調用完成事務操作

    比如:訂單微服務和庫存微服務,下單的同時訂單微服務請求庫存微服務減庫存。

    簡言之:跨JVM進程產生分佈式事務
    在這裏插入圖片描述

  • 單體系統訪問多個數據庫實例

    當單體系統需要訪問多個數據庫時就會產生分佈式事務

    比如:用戶信息和訂單信息分別在兩個MySQL實例存儲,用戶管理系統刪除用戶信息,需要分別刪除用戶信息以及用戶的訂單信息,由於數據分佈在不同的數據實例,需要通過不同的數據庫連接去操作數據,此時產生分佈式事務。

    簡言之:跨數據庫實例產生分佈式事務
    在這裏插入圖片描述

  • 多服務訪問同一個數據庫實例

    比如:訂單服務費和庫存微服務即使訪問同一個數據庫也會產生分佈式事務,原因就是跨JVM進程,兩個微服務持有了不同的數據庫鏈接進行數據庫操作,此時產生分佈式事務。
    在這裏插入圖片描述

二.分佈式事務基礎理論

2.1 CAP理論
2.1.1 分佈式事務CAP

CAP: Consistency Availability Partition tolerance三個詞語的縮寫,分別表示一致性,可用性,分區容錯性(容忍性)

下面我們結合電商系統的場景來理解CAP:
在這裏插入圖片描述

整體流程:

1.商品服務請求主數據庫寫入商品信息

2.主數據庫向商品服務響應寫入成功

3.商品服務請求從數據庫讀取數據

C-Consistency

一致性是指寫操作後的讀操作可以讀取到最新的數據狀態,當數據分佈在多個節點上,從任意節點讀取到的數據都是最新的狀態。

上圖中,商品信息的讀寫要滿足一致性就是要實現如下目標:

1.商品服務寫入主數據庫成功,則向從數據庫查詢新數據也成功。

2.商品服務寫入主數據庫失敗,則向從數據庫查詢新數據也失敗。

如何實現一致性?

1.寫入主數據庫後要將數據同步到從數據庫

2.寫入主數據庫後,在向從數據庫同步期間要將從數據庫鎖定,待同步完成在釋放鎖,以免在新數據寫入成功後,向從數據庫查詢到舊數據。

分佈式系統一致性的特點:

1.由於存在數據同步的過程,寫操作的響應有一定的延遲。

2.爲了保證數據一致性會對資源暫時鎖定,待數據同步完成釋放資源。

3.如果請求數據同步失敗的節點則會返回錯誤信息,一定不會返回舊數據。

A-Availability

可用性是指任何事務操作都可以得到響應結果,且不會出現響應超時或響應錯誤。

上圖中,商品信息讀取滿足可用性就是要實現如下目標:

1.從數據庫接收到數據查詢的請求則立即能夠響應數據查詢結果

2.從數據庫不允許出現響應超時或響應錯誤。

如何實現可用性?

1.寫入主數據庫後要將數據同步到從數據庫

2.由於要保證從數據庫的可用性,不可將從數據庫中的資源進行鎖定

3.即使數據還沒有同步過來,從數據庫也要返回要查詢的數據,哪怕是舊數據,如果連舊數據也沒有則可以按照約定返回一個默認信息,但不能返回錯誤或響應超時。

分佈式系統可用性的特點:

1.所有請求都有響應,且不會出現響應超時或響應錯誤

P-Partition tolerance

通常分佈式系統的每個節點部署在不同的子網,這就是網絡分區,不可避免的會出現由於網絡問題而導致結點之間通信失敗,此時仍可對外提供服務,這叫分區容錯性。

上圖中,商品信息讀寫滿足分區容錯性就是要實現如下目標:

1.主數據庫向從數據庫同步數據失敗不影響讀寫操作。

2.其中一個節點掛點不影響另外一個節點對外提供服務

如何實現分區容錯性?

1.儘量使用異步取代同步操作,例如使用異步方式將數據從主數據庫同步到從數據,這樣節點之間能有效的實現松耦合。

2.添加從數據庫節點,其中一個節點掛了,其他節點還能提供服務。

分佈式分區容錯性的特點:

1.分區容錯性是分佈式系統具備的基本能力

2.1.2 CAP組合方式

在所有分佈式事務場景中不會同時具備CAP三個特性,因爲在具備了P的前提下C和A是不能共存的。

所以在生產中對分佈式事務處理時要根據需求確定滿足CAP的哪兩個方面。

  • AP:

    放棄一致性,追求分區容錯性和可用性,這是很多分佈式系統設計時的選擇。

    例如:

    上面的商品管理,完成可以實現AP,前提是用戶可以接收查詢到的數據在一定時間內不是最新的即可

    通常實現AP都會保證最終一致性,比如:訂單退款,今天退款成功,明日賬戶到賬,只要用戶可以接收在一定時間內到賬即可。

  • CP:

    放棄可用性,追求一致性和分區容錯性,zookeeper就是追求強一致,比如:跨行轉賬,一次轉賬請求要等待雙方銀行系統都完成整個事務纔算完成。

  • CA:

    放棄分區容錯性,即不進行分區,不考慮由於網絡不通或節點掛掉的問題,則可以現實一致性和可用性。那麼系統就不是一個標準的分佈式系統。我們常用的關係型數據就滿足了CA。比如:單體應用,通過本地事務隔離級別實現每個查詢請求都是最新的數據。

2.1.3 總結

通過上面我們學習了CAP理論的相關知識,CAP是一個已經被證實的理論:一個分佈式系統最多隻能同時滿足一致性,可用性和分區容錯性三項中的兩項。它可以作爲我們進行架構設計,技術選型的考量標準,對於大多數互聯網應用的場景,節點多,部署分散,而且集羣規模越來越大,所以節點故障,網絡故障是常態,而且要保證服務可用性達到N個9(99.99…%),並要達到良好的響應性能來提高用戶體驗,因此一般都會做出如下選擇:保證P和A,捨棄C強一致,保證最終一致性。

2.2 BASE理論

BASE是Basically Available(基本可用) ,Soft state(軟狀態)和Eventually consistent(最終一致性)三個短語的縮寫。BASE理論是對CAP中AP的一個擴展,通過犧牲強一致性來獲得可用性,當出現故障允許部分不可用但要保證核心功能可用,允許數據在一段時間內是不一致的,但最終達到一致狀態。滿足BASE理論的事務,我們稱爲“柔性事務”

  • 基本可用:分佈式系統在出現故障時,允許損失部分可用功能,保證核心功能可用。如:電商網站交易付款出現問題,商品依然可用正常瀏覽。
  • 軟狀態:由於不要求強一致性,所以BASE允許系統中存在中間狀態(也叫軟狀態),這個狀態不影響系統可用性,如訂單的“支付中”,“數據同步中”等狀態,待數據最終一致後狀態改爲“成功”狀態
  • 最終一致性:最終一致是指經過一段時間後,所有節點數據都將會達到一致。如訂單的“支付中”狀態,最終會變爲"支付成功"或者"支付失敗",使訂單狀態和實際交易達成一致,但需要一定實際的延遲、等待。

三.分佈式事務解決方案之2PC(兩階段提交)

3.1 什麼是2PC

2PC即兩階段提交協議,是將整個事務流程分爲兩個階段,準備階段(Prepare phase)和提交階段(commit phase),2是指兩個階段,P是指準備階段,C是指提交階段。

比如:張三和李四老友聚餐,飯店老闆要求先買單,才能出單。這時張三和李四分別抱怨近況不如意,都不願意請客,只能AA。只有張三和李四都付款,老闆才能出票安排就餐。但由於張三和李四都是鐵公雞,形成尷尬一幕。

準備階段:老闆要求張三付款,張三付款。老闆要求李四付款,李四付款。

提交階段:老師出票,兩人拿票落座就餐。

例子中形成了一個事務,若張三或李四其中一個人拒絕付款,或錢不夠,店老闆都不會出票,並且會把已收款退回。

整個事務過程由事務管理器和參與者組成,店老闆就是事務管理器,張三和李四就是事務參與者,事務管理器負責決策整個分佈式事務的提交和回滾,事務參與者負責自己本地事務的提交或回滾。

在計算機中部分關係型數據庫如Mysql,Oracle支持兩階段提交協議:

1.準備階段:事務管理器給每個參與者發送Prepare消息,每個數據庫參與者在本地執行事務,並寫本地的Undo和Redo日誌,此時事務沒有提交。

(Undo日誌記錄修改前的數據,用於數據庫回滾,Redo日誌是記錄修改後的數據,用於提交事務後寫入數據文件)

2.提交階段:如果事務管理器收到了參與者的執行失敗或超時消息,直接給每個參與者發送回滾(Rollback)消息;否則,發送提交(Commit);參與者根據事務管理器的指令執行提交或者回滾操作,並釋放事務處理過程中使用的鎖資源。注意:必須在最後階段釋放鎖資源。

下圖展示了2PC的兩個階段,分成功和失敗兩個情況說明:

成功:
在這裏插入圖片描述
失敗:

在這裏插入圖片描述

3.2 解決方案
3.2.1 XA方案

2PC的傳統方案是在數據庫層面實現的,如Oracle,MySql都支持2PC協議,爲了統一標準減少行業內不必要的對接成本,需要定製標準化的處理模型以及接口標準,國際開放標準組織Open Group定義了分佈式事務處理模型DTP

爲了讓大家更明確XA方案的內容,下面使用新用戶註冊送積分爲例:

在這裏插入圖片描述

執行流程如下:

  1. 應用程序(AP)持有用戶庫和積分庫兩個數據源

  2. 應用程序(AP)通過TM通知用戶庫RM新增用戶,同時通知積分庫RM爲改用戶新增積分,RM此時並未提交事務,此時用戶和積分資源鎖定。

  3. TM收到執行回覆,只要有一方失敗則分別向其他RM發起回滾事務,回滾完畢,資源鎖釋放。

  4. TM收到執行回覆,全部成功,此時向所有RM發起提交事務,提交完畢,資源鎖釋放。

DTP模型定義如下角色:

  • AP:即應用程序,可用理解爲使用DTP分佈式事務的程序
  • RM:資源管理器,可用理解爲事務的參與者,一般情況下是指一個數據庫實例,通過資源管理器對該數據庫進行控制,資源管理器控制着分支事務。
  • TM:事務管理器,負責協調和管理事務,事務管理器控制這全局事務,管理事務生命週期,並協調各個RM。全局事務是指分佈式事務處理環境中,需要操作多個數據庫共同完成一個工作,這個工作即是一個全局事務。
  • DTP模型定義TM和RM之間通訊的接口規範爲XA,簡單理解爲數據庫提供的2PC接口協議,基於數據庫的XA協議來實現2PC又稱爲XA方案。
  • 以上三個角色之間的交互方式如下:
    • TM向AP提供應用程序編程接口,AP通過TM提交及回滾事務。
    • TM交易中間件通過XA協議來通知RM數據庫事務的開始,結束以及提交,回滾等。

總結:

整個2PC的事務流程涉及到三個角色AP,RM,TM。AP指的是使用2PC分佈式事務的應用程序;RM指的是資源管理器,控制分支事務;TM指的是事務管理器,控制全局事務。

  • 在準備階段RM執行實際的業務操作,但不提交事務,資源鎖定
  • 在提交階段TM會接收RM在準備階段的執行回覆,只要又任一個RM執行失敗,TM會通知所有RM執行回滾操作,否則,TM會通知所有RM提交該事務。提交階段結束資源鎖釋放。

XA方案的問題:

  • 需要本地數據庫支持XA協議。
  • 資源鎖需要等到兩個階段結束才能釋放,性能較差。
3.2.2 Seata方案

Seata是由阿里中間件團隊發起的開源項目 Fescar,後更名爲Seata,它是一個是開源的分佈式事務框架。 傳統2PC的問題在Seata中得到了解決,它通過對本地關係數據庫的分支事務的協調來驅動完成全局事務,是工作 在應用層的中間件。主要優點是性能較好,且不長時間佔用連接資源,它以高效並且對業務0侵入的方式解決微服 務場景下面臨的分佈式事務問題,它提供AT模式(即2PC),TCC,SAGA 和 XA 模式的分佈式事務解決方案。

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註冊分支事務,該分支事務執行增加積分的邏輯,並將其納入對應全局事務的管轄
  5. 積分服務執行分支事務,向積分表插入一條數據,執行完畢,返回用戶服務
  6. 用戶服務分支事務執行完畢
  7. TM向TC發起準對XID的全局提交或回滾協議
  8. TC調度XID下管轄的全部分支事務完成提交或回滾請求

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

架構層次方面:傳統2PC方案的RM實際上是在數據庫層,RM本質上就是數據庫本身,通過XA協議實現,而Seata的RM是以jar包的形式作爲中間件層部署在應用程序這一側。

兩階段提交方面:傳統2PC無論第二階段的決議是提交還是回滾,事務性資源的鎖都要保持到二階段提交完了後才釋放,而Seata在第一階段就將本地事務提交了,這樣省去了二階段持有鎖的實際,整體提高效率。

3.3 Seata實現2PC事務
3.3.1 業務說明

本示例通過Seata中間件實現分佈式事務,模擬兩個賬戶的轉賬交易過程

兩個賬戶在兩個不同的銀行(張三在bank1、李四在bank2),bank1和bank2是兩個微服務。交易過程是,張三 給李四轉賬指定金額

上述交易步驟,要麼一起成功,要麼一起失敗,必須是一個整體性的事務。

3.3.2 程序組成

數據庫:mysql 5.7

包含bank1和bank2兩個數據庫

JDK 1.8

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 Eureka

3.3.3 創建數據庫
USE `bank1`;

DROP TABLE IF EXISTS `account_info`;

CREATE TABLE `account_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `account_name` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '戶主姓名',
  `account_no` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '銀行卡號',
  `account_password` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '帳戶密碼',
  `account_balance` double DEFAULT NULL COMMENT '帳戶餘額',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_bin ROW_FORMAT=DYNAMIC;

insert  into `account_info`(`id`,`account_name`,`account_no`,`account_password`,`account_balance`) values (2,'張三','1',NULL,1000);

DROP TABLE IF EXISTS `undo_log`;

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=167 DEFAULT CHARSET=utf8;
USE `bank2`;

DROP TABLE IF EXISTS `account_info`;

CREATE TABLE `account_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `account_name` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '戶主姓名',
  `account_no` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '銀行卡號',
  `account_password` varchar(100) COLLATE utf8_bin DEFAULT NULL COMMENT '帳戶密碼',
  `account_balance` double DEFAULT NULL COMMENT '帳戶餘額',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_bin ROW_FORMAT=DYNAMIC;

insert  into `account_info`(`id`,`account_name`,`account_no`,`account_password`,`account_balance`) values (3,'李四的賬戶','2',NULL,0);

DROP TABLE IF EXISTS `undo_log`;

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 DEFAULT CHARSET=utf8;
3.3.4 啓動TC(事務協調器)
  • 下載Seata服務器

    官網:seata.io

    下載地址:https://github.com/seata/seata/releases/download/v0.7.1/seata-server-0.7.1.zip (版本有點低,後續會自行研究高版本)

  • 解壓啓動

    [seata服務端解壓路徑]/bin/seata-server.bat -p 8888 -m file 注:其中8888爲服務端口號;file爲啓動模式,這裏指seata服務將採用文件的方式存儲信息。出現“Server started…”的字樣則表示啓動成功。

3.3.5 工程代碼

dtx-seata-demo

可以根據我寫好的demo創建相應的父工程,bank1,bank2

3.3.6 配置seata

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

## registry.type使用file

registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "file"

  nacos {
    serverAddr = "localhost"
    namespace = "public"
    cluster = "default"
  }
  eureka {
    serviceUrl = "http://localhost:1001/eureka"
    application = "default"
    weight = "1"
  }
  redis {
    serverAddr = "localhost:6379"
    db = "0"
  }
  zk {
    cluster = "default"
    serverAddr = "127.0.0.1:2181"
    session.timeout = 6000
    connect.timeout = 2000
  }
  consul {
    cluster = "default"
    serverAddr = "127.0.0.1:8500"
  }
  etcd3 {
    cluster = "default"
    serverAddr = "http://localhost:2379"
  }
  sofa {
    serverAddr = "127.0.0.1:9603"
    application = "default"
    region = "DEFAULT_ZONE"
    datacenter = "DefaultDataCenter"
    cluster = "default"
    group = "SEATA_GROUP"
    addressWaitTime = "3000"
  }
  file {
    name = "file.conf"
  }
}

config {
  # file、nacos 、apollo、zk
  type = "file"

  nacos {
    serverAddr = "localhost"
    namespace = "public"
    cluster = "default"
  }
  apollo {
    app.id = "seata-server"
    apollo.meta = "http://192.168.1.204:8801"
  }
  zk {
    serverAddr = "127.0.0.1:2181"
    session.timeout = 6000
    connect.timeout = 2000
  }
  file {
    name = "file.conf"
  }
}
##更改service.vgroup_mapping.[springcloud服務名]-fescar-service-group = "default",並修改 service.default.grouplist =[seata服務端地址]

transport {
  # tcp udt unix-domain-socket
  type = "TCP"
  #NIO NATIVE
  server = "NIO"
  #enable heartbeat
  heartbeat = true
  #thread factory for netty
  thread-factory {
    boss-thread-prefix = "NettyBoss"
    worker-thread-prefix = "NettyServerNIOWorker"
    server-executor-thread-prefix = "NettyServerBizHandler"
    share-boss-worker = false
    client-selector-thread-prefix = "NettyClientSelector"
    client-selector-thread-size = 1
    client-worker-thread-prefix = "NettyClientWorkerThread"
    # netty boss thread size,will not be used for UDT
    boss-thread-size = 1
    #auto default pin or 8
    worker-thread-size = 8
  }
}
## transaction log store
store {
  ## store mode: file、db
  mode = "file"

  ## file store
  file {
    dir = "sessionStore"

    # branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
    max-branch-session-size = 16384
    # globe session size , if exceeded throws exceptions
    max-global-session-size = 512
    # file buffer size , if exceeded allocate new buffer
    file-write-buffer-cache-size = 16384
    # when recover batch read size
    session.reload.read_size = 100
    # async, sync
    flush-disk-mode = async
  }

  ## database store
//  db {
//    driver_class = "com.mysql.jdbc.Driver"
//    url = "jdbc:mysql://172.16.0.203:3306/bank?useUnicode=true"
//    user = "root"
//    password = "itcast0430"
//  }
  db {
    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.
    datasource = "dbcp"
    ## mysql/oracle/h2/oceanbase etc.
    db-type = "mysql"
    url = "jdbc:mysql://127.0.0.1:3306/seata"
    user = "root"
    password = "mysql"
    min-conn = 1
    max-conn = 3
    global.table = "global_table"
    branch.table = "branch_table"
    lock-table = "lock_table"
    query-limit = 100
  }
}

service {
  #vgroup->rgroup
  vgroup_mapping.seata-demo-bank1-fescar-service-group = "default"
  #only support single node
  default.grouplist = "127.0.0.1:8888"
  #degrade current not support
  enableDegrade = false
  #disable
  disable = false
}
client {
  async.commit.buffer.limit = 10000
  lock {
    retry.internal = 10
    retry.times = 30
  }
}

/**
關於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 中的配置保持 一致。
#  cloud:
#   alibaba:
#      seata:
#        tx-service-group: seata-demo-bank1-fescar-service-group
*/
3.3.7 Seata執行流程

正常流程

在這裏插入圖片描述

回滾流程

在這裏插入圖片描述

要點說明

  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 並執行,以完成分支事務回滾到之前的狀態,如果回滾失敗則會重試回滾操作。
3.4 小結

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

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

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

3、每個數據都需要創建undo_log表,此表是seata保證本地事務一致性的關鍵。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章