zoukankan      html  css  js  c++  java
  • 【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';

        得到前镜像:

    idnamesince
    1 TXC 2014

      3、执行业务 SQL:更新这条记录的 name 为 'GTS'。

      4、查询后镜像:根据前镜像的结果,通过 主键 定位数据。

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

        得到后镜像:

    idnamesince
    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 表:数据被删除

       验证二阶段提交成功

  • 相关阅读:
    20120110 自己写的基于jquery的翻页效果
    搜来的 可爱的if ie
    哎~~~纠结死了的终于解决的i6的fixed属性
    2011815发现可好的js繁简转换代码 写这些的人。。好厉害呀 收藏了~~~
    网站制作CSS图片转换滤镜代码(貌似只对ie有用。。。)
    2011811 右下角弹出渐隐的广告代码 可以关闭 可以缩小 还各种兼容(ff opera ie6、7、8都试过了)值得保留哎~~~
    20120604 自己写的基于jquery的类似百度贴吧头像提示效果
    UFT textUtil object 解决奇怪问题
    UFT send request & get response
    UFT connect sql (1)
  • 原文地址:https://www.cnblogs.com/h--d/p/13034425.html
Copyright © 2011-2022 走看看