大綱
1.Seata分布式事務框架簡介
2.Seata AT模式實現分布式事務的機制
3.Seata AT模式下的寫隔離機制
4.Seata AT模式下的讀隔離機制
5.官網示例說明Seata AT模式的工作機制
6.Seata TCC模式的介紹以及與AT模式區別
7.Seata Saga模式的介紹
8.單服務多個庫的分布式事務支持
9.Seata的AT、TCC、Saga三種模式對比
10.基于RocketMQ的可靠消息最終一致性事務
11.Seata官方分布式事務例子
1.Seata分布式事務框架簡介
(1)Seata的特色功能
(2)Seata的術語
Seata是一款分布式事務解決方案,為用戶提供了AT、TCC、SAGA和XA事務模式,致力于在微服務架構下提供高性能和簡單易用的分布式事務服務。
(1)Seata的特色功能
一.微服務框架集成支持
已支持Dubbo、Spring Cloud、Sofa-RPC、Motan和gRPC等RPC框架。
二.AT模式
提供無侵入自動補償的事務模式,目前已支持MySQL、Oracle、PostgreSQL、TiDB和MariaDB。
三.TCC模式
支持TCC模式并可與AT混用,靈活度更高。
四.SAGA模式
為長事務提供的解決方案,提供編排式與注解式。
五.XA模式
支持已實現XA接口的數據庫的XA模式,目前已支持MySQL、Oracle、TiDB和MariaDB。
六.高可用
支持計算分離集群模式,水平擴展能力強的數據庫和Redis存儲模式。
(2)Seata的術語
一.TC(Transaction Coordinator)—事務協調者
用來維護全局和分支事務的狀態,驅動全局事務提交或回滾。
二.TM(Transaction Manager)—事務管理器
用來定義全局事務的范圍:開始全局事務、提交或回滾全局事務。
三.RM(Resource Manager)—資源管理器
用來管理分支事務處理的資源,與TC交談以注冊分支事務和報告分支事務的狀態,并驅動分支事務提交或回滾。
2.Seata AT模式實現分布式事務的機制
(1)前提
(2)整體機制
(1)前提
一.基于支持本地ACID事務的關系型數據庫
二.Java應用 + 通過JDBC訪問數據庫
(2)整體機制
兩階段提交協議的演變:
一階段:首先業務數據和回滾日志記錄在同一個本地事務中提交,然后釋放本地鎖和連接資源。
二階段:提交異步化,非常快速地完成,回滾通過一階段的回滾日志進行反向補償。
3.Seata AT模式下的寫隔離機制
(1)Seata在AT模式下的寫隔離機制
(2)Seata在AT模式下的寫隔離例子
(3)Seata AT模式寫隔離下的補償執行
(4)為什么Seata AT模式要設計寫隔離機制
(1)Seata在AT模式下的寫隔離機制
一階段本地事務提交前,需要確保先拿到全局鎖。如果拿不到全局鎖,就不能提交本地事務。拿全局鎖的嘗試被限制在一定時間范圍內,超出時間范圍將被放棄,并回滾本地事務,釋放本地鎖。
(2)Seata在AT模式下的寫隔離例子
以一個示例來說明:兩個全局事務tx1和tx2,分別對m字段進行更新操作,m的初始值是1000。
tx1先開始,開啟本地事務,拿到本地鎖,更新操作m=1000-100=900。本地事務提交前,先拿到該記錄的全局鎖 ,本地事務提交后釋放本地鎖。
tx2后開始,開啟本地事務,拿到本地鎖,更新操作m=900-100=800。本地事務提交前,嘗試拿該記錄的全局鎖。
tx1全局提交前,該記錄的全局鎖被tx1持有,tx2需要重試等待獲取全局鎖。tx1二階段全局提交,釋放全局鎖。tx2拿到全局鎖后,提交其本地事務。
(3)Seata AT模式寫隔離下的補償執行
如果tx1的二階段全局回滾,則tx1需要重新獲取該數據的本地鎖,進行反向補償的更新操作,實現分支的回滾。
此時如果tx2仍在等待該數據的全局鎖,同時持有本地鎖,則tx1的分支回滾會失敗,tx1的分支回滾會一直重試,直到tx2的全局鎖等鎖超時,需要放棄全局鎖 + 回滾本地事務 + 釋放本地鎖,此時tx1的分支回滾才能最終成功。
(4)為什么Seata AT模式要設計寫隔離機制
由于整個過程全局鎖在tx1結束前一直是被tx1持有的,所以寫隔離機制可以保證不會發生臟寫的問題。
4.Seata AT模式下的讀隔離機制
(1)Seata AT模式的讀隔離機制介紹
(2)Seata AT模式的讀隔離機制實現
(1)Seata AT模式的讀隔離機制介紹
在數據庫本地事務隔離級別讀已提交(Read Committed)或以上的基礎上,Seata AT模式的默認全局隔離級別是讀未提交(Read Uncommitted)。
如果應用在特定場景下,必需要求全局的讀已提交,目前Seata的方式是通過SELECT FOR UPDATE語句的代理來實現。
(2)Seata AT模式的讀隔離機制實現
SELECT FOR UPDATE語句的執行會申請全局鎖。如果全局鎖被其他事務持有,則釋放本地鎖(回滾SELECT FOR UPDATE語句的本地執行)并重試。
在這個過程中,查詢是被阻塞住的。直到拿到全局鎖,即讀取的相關數據是已提交的,才返回。
出于總體性能上的考慮,Seata目前的方案并沒有對所有SELECT語句都進行代理,僅針對FOR UPDATE的SELECT語句。
5.官網示例說明Seata AT模式的工作機制
(1)一階段的工作過程
(2)二階段——回滾的工作過程
(3)二階段——提交的工作過程
(4)使用Seata AT模式需要創建回滾日志表
以一個示例來說明整個AT分支的工作過程:
業務表:product
+-------+--------------+-------+
| Field | Type | Key |
+-------+--------------+-------+
| id | bigint(20) | PRI |
+-------+--------------+-------+
| name | varchar(100) | |
+-------+--------------+-------+
| since | varchar(100) | |
+-------+--------------+-------+
AT分支事務的業務邏輯:
update product set name = 'GTS' where name = 'TXC';
(1)一階段的工作過程
步驟一:解析SQL得到SQL的類型、表、條件等相關的信息。比如類型是UPDATE、表是product、條件是where name = 'TXC'。
步驟二:查詢前鏡像。也就是根據解析得到的條件信息,生成查詢語句,定位數據。
select id, name, since from product where name = 'TXC';//得到前鏡像如下:
+-------+-------+-------+
| id | name | since |
+-------+-------+-------+
| 1 | TXC | 2014 |
+-------+-------+-------+
步驟三:執行業務SQL。更新這條記錄的name為'GTS'。
步驟四:查詢后鏡像。根據前鏡像的結果,通過主鍵定位數據。
select id, name, since from product where id = 1;//得到后鏡像如下:
+-------+-------+-------+
| id | name | since |
+-------+-------+-------+
| 1 | GTS | 2014 |
+-------+-------+-------+
步驟五:插入回滾日志。把前后鏡像數據以及業務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
(2)二階段——回滾的工作過程
步驟一:收到TC的分支回滾請求,開啟一個本地事務執行如下操作。
步驟二:通過XID和Branch ID查找到相應的UNDO LOG記錄。
步驟三:拿UNDO LOG中的后鏡像與當前數據進行數據校驗。如果有不同,說明數據被當前全局事務之外的動作做了修改。這種情況,需要根據配置策略來做處理。
步驟四:根據UNDO LOG中的前鏡像和業務SQL信息生成并執行回滾語句。
步驟五:提交本地事務并把執行結果(即分支事務回滾的結果)上報給TC。
(3)二階段——提交的工作過程
步驟一:收到TC的分支提交請求,把請求放入一個異步任務的隊列中,然后馬上返回提交成功的結果給TC。
步驟二:異步任務階段執行分支提交請求,將異步和批量地刪除相應UNDO LOG記錄。
(4)使用Seata AT模式需要創建回滾日志表
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,PRIMARY KEY (`id`),UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
6.Seata TCC模式的介紹以及與AT模式區別
(1)Seata TCC模式的介紹
(2)TCC模式與AT模式的區別
(1)Seata TCC模式的介紹
TCC = Try + Commit + Cancel。一個分布式的全局事務,整體是兩階段提交的模型。全局事務是由若干分支事務組成,分支事務要滿足兩階段提交的模型要求。
即需要每個分支事務都具備自己的:一階段Prepare行為(Try行為),二階段Commit或Rollback行為(Commit + Cancel行為)。
(2)TCC模式與AT模式的區別
所謂TCC模式,是指支持把自定義的分支事務納入到全局事務的管理中。其實一開始,Seata只有TCC模式,后來才加入AT模式。但TCC模式太麻煩了,每個功能都需要實現三套SQL邏輯,AT模式其實是對TCC模式的簡化。
AT模式基于支持本地ACID事務的關系型數據庫:
一階段Prepare行為:在本地事務中,一起提交業務數據更新和相應回滾日志記錄。
二階段Commit行為:馬上成功結束,自動 + 異步 + 批量清理回滾日志。
二階段Rollback行為:通過回滾日志,自動生成補償操作,完成數據回滾。
TCC模式則不依賴于底層數據資源的事務支持:
一階段Prepare行為:調用自定義Prepare邏輯。
二階段Commit行為:調用自定義Commit邏輯。
二階段Rollback行為:調用自定義Rollback邏輯。
7.Seata Saga模式的介紹
Saga模式是Seata提供的長事務解決方案。在Saga模式中,業務流程中每個參與者都提交本地事務,當出現某一個參與者失敗則補償前面已經成功的參與者。一階段正向服務和二階段補償服務都由業務開發實現。
Saga模式的正向服務可以理解成是TCC模式的Try階段 + Commit階段,逆向補償服務可以理解成是TCC模式的Cancel階段。
一.適用場景
場景一:業務流程長、業務流程多
場景二:無法提供TCC模式要求的三個接口
比如參與者包含其它公司,或者遺留的老系統服務。
二.優勢
一階段提交本地事務,無鎖 + 高性能。
事件驅動架構,參與者可異步執行,高吞吐。
補償服務易于實現。
三.缺點
不保證隔離性,寫不隔離。
8.單服務多個庫的分布式事務支持
單個服務對接了多個庫。比如該服務處理一個請求時,需要更新多個數據庫。分支事務是分布在多個數據庫上的,并不是分布在多個服務上的。Seata也天然支持這種情況下的分布式事務。
每個數據庫上的事務也都會到Seata上注冊一個分支事務。注冊之后,各個分支事務也和Seata的AT模式一樣:申請本地鎖 + 生成undo log + 申請全局鎖 + 在其對應數據庫上提交增刪改。
9.Seata的AT、TCC、Saga三種模式對比
AT模式適用于底層存儲都相同的情況,比如都是MySQL等。一般選用AT模式即可,簡單方便。
TCC模式適用于底層存儲是異構的情況,比如MySQL + Redis + ES等。TCC模式一般在try階段寫入一條數據并標記未生效狀態,然后在commit階段才正式標記為正常生效狀態。
TCC模式最大的優點就是很靈活。即使事務失敗了,try階段寫入的數據基本也不會影響線上業務。TCC模式特別適用于異構存儲要支持事務的情況。
Saga模式適用于異構系統、長流程、改造成TCC特別復雜繁瑣的情況。
10.基于RocketMQ的可靠消息最終一致性事務
同步事務:在Seata的AT、TCC、Saga中選一種。
異步事務:使用RocketMQ的事務機制或者自己實現一套最終一致性事務框架。
11.Seata官方分布式事務例子
https://seata.io/zh-cn/docs/user/quickstart.html