• Seata设计核心原理


    Seata官网: Seata 官网

    设计核心点

    Seata中涉及三个角色

    TC:  事务协调者,分布式事务的核心实现,Seata把它单独成一个服务器了

    TM:  事务开启者,用来发起全局事务的,(其实也可以充当TC,只不过Seata进行隔离了)

    RM: 资源管理器,每个单独事务的参与者

    Seata支持多种模式

    强一致性的模式

    AT:也是Seata首推的模式,通过undo_log日志配合本地事务

    XA:  利用数据库本身支持的分布式事务处理

    最终一致性模式:

    TCC:通过自己开发资源锁定,提交,回滚等接口

    Saga:  长事务

    全局事务和本地事务的区别

    本地事务:一般都是数据库保证的,例如Mysql

    全局事务:当有分布式事务时出现的一个概念,保证多个本地事务的正确执行

    当有全局事务时,会有一个全局的xid标识,然后每个本地事务作为一个分支事务会有bid与唯一的xid进行绑定和关联

    xid的处理

            每个分支事务都需要持有xid的数据,seata是基于以下几步做处理的

    1,首先,TM事务先开启一个全局事务,然后获得一个Xid

    2,获取Xid后当前的RM会把它放到 RootContext.bind(xid)中,其实就是一个ThreadLocal

    3.   当调用其他微服务的时候通过SeataRestTemplateInterceptor拦截器拿取RootContext.getXID()获取xid然后往后面的微服务进行传输(该类实现了ClientHttpRequestInterceptor扩展点)

    4.   其他微服务从SeataHandlerInterceptor中获取xid,然后又把它设置到自己的ThreadLocal中了,这样一来就实现了xid的往后传输了(该类实现了HandlerInterceptor扩展点

      以上便是seata对于xid扩展点的设计

    AT模式的设计

            AT模式也是seata首推的模式,它通过undo_log日志和层层代理来对分布式事务进行处理,以下是它具体的流程

    1. 我们使用GlobalTransactional注解标记方法
    2. seata扫描该注解进行代理调用,有一个全局的GlobalTransaction接口,默认的实现类为DefaultGlobalTransaction
    3. 然后通过代理调用GlobalTransaction的begin开启全局事务方法,该方法会想TC发起一个开启全局事务的请求,然后TC返回一个xid
    4. 接着当前微服务按上面的流程处理xid
    5. 然后所有的微服务在调用commit提供本地事务时会被seata提供的ConnectionProxy进行代理,在调用commit方法,seata会先判断当前事务是否是全局事务(判断ThreadLocal中有没有XID数据),如果是的话会根据sql语句进行前置镜像的保存,然后执行sql,接着保存后置镜像,然后会向TC注册一个分支事务,如果本地事务提交失败还会发送一个报告给TC
    6. 如果每个分支事务都执行成功了那么TC后台会有个定时器查询全局事务的分布事务,如果全部都提交成功的话,那么就会循环所有分支事务然后由TC调用RM的branchCommit方法,如果有一个失败的话就会调用branchRollback方法
    7. 以上便是大概的交互流程,如果要看详细的话可能要去看源码才知道了

    AT模式的优势

    •  不需要持有connection的连接了,会提升数据库的性能
    •  TC单节点问题可以通过部署多台来解决
    •  分支事务的二阶段提交有了相应的校验保证能执行完成

    Seata的全局锁

            分支事务在注册的时候是需要在TC那边获取一把全局锁的,TC的全局锁其实就是往数据表插入一个xidkey的字段,该字段是唯一性,同时只能有一个全局事务持有

     全局锁的作用

            写隔离:因为AT模式下第一阶段本地事务其实已经提交了,所以本地事务读到的数据已经是更改后的了,如果此时有其他全局事务读到了该数据,实际上是等于读到了未提交的数据,那么就有可能会出现脏读的问题,所以seata才会设计全局锁来解决这个问题,此时如果有其他全局事务要去更改这个数据,它实际上是拿不到锁的,所以就会阻塞在那里,直到上面的全局事务执行完成才能获取到数据

            读隔离:用 for update 配合 GlobalLock注解seata帮我们实现了读隔离,当一个方法标记了GlobalLock后,那么有另一个GlobalLock方法要去读同一个数据,也会被阻塞那里,等到前面持有锁的线程释放锁以后就会获取到了

    总结

            seata核心的要求就是TC,还有就是对于分布式事务的一个设计方案,然后就是seata大量使用了代理来处理逻辑,这个也是比较值得我们借鉴的,另一个值得借鉴的就是使用ThreadLocal加上其他扩展点实现了xid的传输

            对于我自己来说也是这样,如何把学到的知识用文字表达出来也是比较考验我自己的,以后也会慢慢加强这方面的能力

  • 相关阅读:
    tensorflow-serving实战
    [机缘参悟-75]:谈谈“玻璃心”与“钝感力”
    设计模式:工厂模式和抽象工厂模式的区别
    支持OAuth2.0协议认证,JumpServer堡垒机v2.25.0发布
    VScode常用快捷键
    anime4k 在真机租用上的应用尝试
    java JVM原理与常识知识点
    力控软件与2台200Smart之间无线以太网通信
    Sora 使用教程,新手小白可用
    【jeecg-boot】解决页面跳转问题:
  • 原文地址:https://blog.csdn.net/zxc_user/article/details/127914033