• 分布式事务--各方案的最通俗讲解


    分布式事务的方案:
    XA/TCC/本地消息表/最大努力通知/可靠消息最终一致性/(saga/seata)
     
    1.XA(二段提交/2PC) :数据库有支持XA的协议的,所以其实XA是在数据库层面的操作,不是服务层面的操作
    第一阶段:询问
    第二阶段:执行
    一般是在多数据源跨库上执行~不适合在微服务架构上,微服务架构思想是每个微服务只执行一个库,需要调用业务只能通过暴露接口进行
     
    ---------------------------------- 
    2.TCC(try-confirm-cancel)
    try:主要是做检查后续的操作能否执行,例如扣款的话需要锁住金额同时查看扣款余额是否足够等
    confirm:执行具体的操作
    cancel:是一个补偿机制需要写补偿逻辑,例如某一个服务扣款失败,某一个成功,那么成功的需要把原来扣取的款给加回去
    特点:是跟业务严重的耦合和侵入,同样的cancel不同业务实现都会不一样,一般在严重需要一致性的场景才会使用TCC 例如跟资金相关的~
     
    ps:TCC需要事务协调器来协助完成上面操作这些东西就不说了,都是实现细节,具体可以看对应的文章
     
    ----------------------------------
    3.本地消息表方案(ebay采用)
       1)主动方和被动方都要在本地存一个消息表
       2)主动方执行成功后在他的本地消息表上同时插入一条消息状态为'待确认'(注意:主动执行方操作和本地消息表的操作需要在同一事务上),同时发送一条消息到MQ让被动方消费,同时想办法监听被动方是否执行成功(轮训或者基于zookeeper监听)
       3)被动方消费数据,先在本地消息表插入数据,同时执行自己的业务(注意:被动方业务操作和本地消息表在同一事务上,同时本地消息表需要有唯一键保证不重复消费)
       4)如果成功主动方更新自己的本地消息表的状态为'成功',否则定时轮训'待确认'的消息表知道发送到MQ上让被动方执行
    缺点:大量依赖本地消息表
     
    ---------------------------------- 
    4.最大努力通知方案
       业务活动的主动方在完成处理之后向业务活动的被动方发送消息,允许消息丢失。业务活动的被动方根据定时策略,向业务活动的主动方查询,恢复丢失的业务消息
     
    ---------------------------------- 
    5.可靠消息最终一致性方案(这个方案使用比较多,有点类似本地消息表只不过消息表放在MQ,一般用于扣库存)
        1)就是基于MQ的事务机制(RocketMQ[RocketMQ如果发现主动方成功了,发送确认给MQ时失败,RocketMQ会主动轮训自己存储的prepare的消息,超过一定时间的数据会回调对应主动方的回调接口询问情况]或者RabbitMQ),保证消息发送和主动方事务在同一事务中,保证主动方成功消息发送成功主动方失败消息失败
        2)接着就是被动方消费消息,直至到成功为止(注意消费需要保证幂等),如果消费放多次都不成功,那么就想办法通知主动方进行回滚或者人工来回滚和补偿
     
    ----------------------------------
    saga模式和TCC区别
      简单点saga就是比TCC少了try:
       Saga的核心就是补偿,一阶段就是服务的正常顺序调用(数据库事务正常提交),如果都执行成功,则第二阶段则什么都不做;但如果其中有执行发生异常,则依次调用其补偿服务来保证最终的一致性。
       TCC的特点在于业务资源检查与加锁,一阶段进行校验,资源锁定,如果第一阶段都成功,二阶段对锁定资源进行交易逻辑,否则,对锁定资源进行释放。
     
    ---------------------------------
    seata原理(AT模式)(跟XA不一样的是第一阶段就提交,第二阶段是进行是否回滚的确认):
    实际就是第一阶段先提交并保留需要回滚的信息,然后第二段就确认是否要回滚,他主要特点是可以解析SQL提交前的数据信息后续用于回滚
    流程如下:
    第一阶段:
        1.解析sql语句,得到 SQL 的类型(UPDATE),表(product),条件(where name = 'ABC')等相关的信息。
        2.查询老数据,根据上面的where语句sql,去数据库查询原始的数据。
                如 select * from product where name = 'ABC';得到原始的数据,如该行id=1,然后记录下来。
        3.执行第一步的sql语句,即执行update,修改数据库的该记录的值。(默认是隔离级别是读未提交)
        4.查询修改后的值,select * from product where id =1.得到该行值,记录下来。
        5.插入回滚日志,将老值、新值以及sql语句组成一个将来可用于回滚的日志,插入到UNDO_LOG表
        6.向TC server注册分支,申请product表,id=1的行的全局锁。注意,这个全局锁是相对于所有可能的同时在执行的分布式事务而言的。一旦某个分支,获取了该记录的全局锁,在解锁之前,任何其他的分布式事务,不能修改该数据。
        7.本地事务提交,将自己的本地事务、和前面的UNDO LOG一起提交。
        8.将本地事务提交的结果上报给TC server。如成功、失败
    第二阶段:
        成功的情况:分支收到了TC下发的成功请求,立马返回我已OK的结果给TC,然后异步执行删除UNDO LOG的操作。因为成功了,所以用来回滚的UNDO LOG就没意义了,异步删除掉就好。
        失败的情况:
            1.分支收到了TC下发的失败请求,开始执行回滚逻辑。
            2.通过 XID 和 Branch ID 查找到相应的 UNDO LOG 记录。
            3.数据校验:拿 UNDO LOG 中的后镜与当前数据进行比较,如果有不同,说明数据被当前全局事务之外的动作做了修改。
            4.根据 UNDO LOG 中的前镜像和业务 SQL 的相关信息生成并执行回滚的语句。
              update product set name = 'ABC' where id = 1;
            5.提交本地事务。并把本地事务的执行结果(即分支事务回滚的结果)上报给 TC 
     
    ---------------------------------
    ps:
    1.分布式事务不应该太多~应该尽量通过监控错误日志信息的方式 通知快速修复数据等,大量的分布式事务会增加系统的复杂性降低吞吐量~90%的都不应该用分布式事务解决
    2.一般扣库存,订单那些采用可靠消息最终一致性性方案,跟金钱有关需要严格保证的采用TCC,但是像发短信,积分等等不太重要的业务不要使用分布式事务解决,通过事前监控时候快速通知解决来搞定
     
     
  • 相关阅读:
    XML和HTML中常用转义字符:
    特殊符号大全
    CSS规范
    兼容ie6,ie7,ie8,firefox,chrome浏览器的代码片段
    模拟select选择器
    一行代码解决IE6/7/8/9/10兼容问题
    响应式页面之秘籍
    Global 全局样式基本设置
    webAPP meta 标签大全
    随笔小计 --
  • 原文地址:https://www.cnblogs.com/danvid/p/12202727.html
Copyright © 2020-2023  润新知