【SpringCloud】Spring Cloud Alibaba 之 Seata 分布式事務原理(三十七)


Seata 分布式事務原理 

Seata整體機制

  兩階段提交協議的演變:

  • 一階段:業務數據和回滾日志記錄在同一個本地事務中提交,釋放本地鎖和連接資源。

  • 二階段:

    • 提交異步化,非常快速地完成。
    • 回滾通過一階段的回滾日志進行反向補償。

一階段

  過程:

  1、解析 SQL:得到 SQL 的類型(UPDATE),表(product),條件(where name = 'TXC')等相關的信息。

  2、查詢前鏡像:根據解析得到的條件信息,生成查詢語句,定位數據。

1 select id, name, since from product where name = 'TXC';

    得到前鏡像:

id name since
1 TXC 2014

  3、執行業務 SQL:更新這條記錄的 name 為 'GTS'。

  4、查詢后鏡像:根據前鏡像的結果,通過 主鍵 定位數據。

1 select id, name, since from product where id = 1;

    得到后鏡像:

id name since
1 GTS 2014

  5、插入回滾日志:把前后鏡像數據以及業務 SQL 相關的信息組成一條回滾日志記錄,插入到 UNDO_LOG 表中。

 1 {
 2     "branchId": 641789253,
 3     "undoItems": [{
 4         "afterImage": {
 5             "rows": [{
 6                 "fields": [{
 7                     "name": "id",
 8                     "type": 4,
 9                     "value": 1
10                 }, {
11                     "name": "name",
12                     "type": 12,
13                     "value": "GTS"
14                 }, {
15                     "name": "since",
16                     "type": 12,
17                     "value": "2014"
18                 }]
19             }],
20             "tableName": "product"
21         },
22         "beforeImage": {
23             "rows": [{
24                 "fields": [{
25                     "name": "id",
26                     "type": 4,
27                     "value": 1
28                 }, {
29                     "name": "name",
30                     "type": 12,
31                     "value": "TXC"
32                 }, {
33                     "name": "since",
34                     "type": 12,
35                     "value": "2014"
36                 }]
37             }],
38             "tableName": "product"
39         },
40         "sqlType": "UPDATE"
41     }],
42     "xid": "xid:xxx"
43 }
View Code

  6、提交前,向 TC 注冊分支:申請 product 表中,主鍵值等於 1 的記錄的 全局鎖 。

  7、本地事務提交:業務數據的更新和前面步驟中生成的 UNDO LOG 一並提交。

  8、將本地事務提交的結果上報給 TC。

二階段-回滾

  1、收到 TC 的分支回滾請求,開啟一個本地事務,執行如下操作。

  2、通過 XID 和 Branch ID 查找到相應的 UNDO LOG 記錄。

  3、數據校驗:拿 UNDO LOG 中的后鏡與當前數據進行比較,如果有不同,說明數據被當前全局事務之外的動作做了修改。這種情況,需要根據配置策略來做處理,詳細的說明在另外的文檔中介紹。

  4、根據 UNDO LOG 中的前鏡像和業務 SQL 的相關信息生成並執行回滾的語句:

1 update product set name = 'TXC' where id = 1;

  5、提交本地事務。並把本地事務的執行結果(即分支事務回滾的結果)上報給 TC。

二階段-提交

  1、收到 TC 的分支提交請求,把請求放入一個異步任務的隊列中,馬上返回提交成功的結果給 TC。

  2、異步任務階段的分支提交請求將異步和批量地刪除相應 UNDO LOG 記錄。

Seata原理機制驗證

  驗證項目使用上一章項目,搭建參考:【SpringCloud】Spring Cloud Alibaba 之 Seata 分布式事務中間件(三十六)

  項目中TC、TM、RM關系如下:

  

一階段-驗證

  1、調試啟動項目,在order項目中,遠程調用庫存服務扣減庫存前,增加斷點

    

  2、訪問地址:http://localhost:9011/order/create?userId=1&productId=1&count=10&money=100,創建訂單

  3、當程序運行到斷點出,已經運行的創建訂單業務,准備調用庫存服務,查看數據庫(order)中的數據

    表order中,有一條數據

    

    表undo_log,有一條數據

    

    其中rollback_info,是一個json,里面內容如下:

    beforeImage:表示前鏡像,內容為空表示SQL執行前記錄未創建

    afterImage:表示后鏡像,內容為SQL執行后,記錄更新后的值

 1 {
 2     "@class":"io.seata.rm.datasource.undo.BranchUndoLog",
 3     "xid":"192.168.1.4:8091:2013220742",
 4     "branchId":2013220749,
 5     "sqlUndoLogs":[
 6         "java.util.ArrayList",
 7         [
 8             {
 9                 "@class":"io.seata.rm.datasource.undo.SQLUndoLog",
10                 "sqlType":"INSERT",
11                 "tableName":"`order`",
12                 "beforeImage":{
13                     "@class":"io.seata.rm.datasource.sql.struct.TableRecords$EmptyTableRecords",
14                     "tableName":"order",
15                     "rows":[
16                         "java.util.ArrayList",
17                         [
18 
19                         ]
20                     ]
21                 },
22                 "afterImage":{
23                     "@class":"io.seata.rm.datasource.sql.struct.TableRecords",
24                     "tableName":"order",
25                     "rows":[
26                         "java.util.ArrayList",
27                         [
28                             {
29                                 "@class":"io.seata.rm.datasource.sql.struct.Row",
30                                 "fields":[
31                                     "java.util.ArrayList",
32                                     [
33                                         {
34                                             "@class":"io.seata.rm.datasource.sql.struct.Field",
35                                             "name":"id",
36                                             "keyType":"PRIMARY_KEY",
37                                             "type":-5,
38                                             "value":[
39                                                 "java.lang.Long",
40                                                 10
41                                             ]
42                                         },
43                                         {
44                                             "@class":"io.seata.rm.datasource.sql.struct.Field",
45                                             "name":"user_id",
46                                             "keyType":"NULL",
47                                             "type":-5,
48                                             "value":[
49                                                 "java.lang.Long",
50                                                 1
51                                             ]
52                                         },
53                                         {
54                                             "@class":"io.seata.rm.datasource.sql.struct.Field",
55                                             "name":"product_id",
56                                             "keyType":"NULL",
57                                             "type":-5,
58                                             "value":[
59                                                 "java.lang.Long",
60                                                 1
61                                             ]
62                                         },
63                                         {
64                                             "@class":"io.seata.rm.datasource.sql.struct.Field",
65                                             "name":"count",
66                                             "keyType":"NULL",
67                                             "type":4,
68                                             "value":10
69                                         },
70                                         {
71                                             "@class":"io.seata.rm.datasource.sql.struct.Field",
72                                             "name":"money",
73                                             "keyType":"NULL",
74                                             "type":3,
75                                             "value":[
76                                                 "java.math.BigDecimal",
77                                                 100
78                                             ]
79                                         },
80                                         {
81                                             "@class":"io.seata.rm.datasource.sql.struct.Field",
82                                             "name":"status",
83                                             "keyType":"NULL",
84                                             "type":4,
85                                             "value":0
86                                         }
87                                     ]
88                                 ]
89                             }
90                         ]
91                     ]
92                 }
93             }
94         ]
95     ]
96 }

  4、查看 seata 庫的

    branch_table 表

    驗證了向TC注冊了分支

    

    global_table 表

    驗證了全局事務ID

    

    lock_table 表

    驗證了行鎖

    

二階段-回滾驗證

  1、當業務出錯或超時回滾時,查看 order 庫 

    order 表 :數據回滾

    undo_log 表 :被清空、回滾

  2、查看 seata 庫的 

    branch_table 表:數據回滾、被清空

    global_table 表:數據回滾、被清空

    lock_table 表:數據回滾、被清空

  驗證二階段回滾成功

二階段-提交驗證

   1、當業務正常實現,事務提交,查看 order 庫 

    order 表 :數據改變

    undo_log 表 :數據被刪除

  2、查看 seata 庫的 

    branch_table 表:數據被刪除

    global_table 表:數據被刪除

    lock_table 表:數據被刪除

   驗證二階段提交成功

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM