zoukankan      html  css  js  c++  java
  • 【分布式事务】分布式事务解决方案

    一、第一种方案:能不用分布式事务就不用

    明确系统是否真的需要分布式事务;

    因为不论任何一种分布式解决方案都会增加你系统的复杂度,这样的成本还是挺高的,千万不要因为追求某些设计,而引入不必要的成本和复杂度。

    二、第二种方案:XA 分布式事务 (MySQL是支持XA事务的)

    属于2PC;
    XA是由X/Open组织提出的分布式事务的规范。

    X/Open DTP(X/Open Distributed Transaction Processing Reference Model) 是X/Open 这个组织定义的一套分布式事务的标准,也就是了定义了规范和API接口,由这个厂商进行具体的实现。这个思想在java 平台里面到处都是。
    X/Open DTP 定义了三个组件: AP,TM,RM
    AP(Application Program):也就是应用程序,可以理解为使用DTP的程序
    RM(Resource Manager):资源管理器,这里可以理解为一个DBMS系统,或者消息服务器管理系统,应用程序通过资源管理器对资源进行控制。资源必须实现XA定义的接口
    TM(Transaction Manager):事务管理器,负责协调和管理事务,提供给AP应用程序编程接口以及管理资源管理器
    其中,AP 可以和TM 以及 RM 通信,TM 和 RM 互相之间可以通信,DTP模型里面定义了XA接口,TM 和 RM 通过XA接口进行双向通信,例如:TM通知RM提交事务或者回滚事务,RM把提交结果通知给TM。AP和RM之间则通过RM提供的Native API 进行资源控制,这个没有进行约API和规范,各个厂商自己实现自己的资源控制,比如Oracle自己的数据库驱动程序。

    三、第三种方案:TCC 方案
    属于2PC;

    TCC 模型是把锁的粒度完全交给业务处理,它需要每个子事务业务都实现Try-Confirm / Cancel 接口。

    Try:
      尝试执行业务
      完成所有业务检查(一致性)
      预留必须业务资源(准隔离性)
    Confirm:
      确认执行业务;
      真正执行业务,不作任何业务检查
      只使用Try阶段预留的业务资源
      Confirm 操作满足幂等性
    Cancel:
      取消执行业务
      释放Try阶段预留的业务资源
      Cancel操作满足幂等性

    这三个阶段,都会按本地事务的方式执行。不同于 XA的prepare ,TCC 无需将 XA 的投票期间的所有资源挂起,因此极大的提高了吞吐量。

    四、第四种方案:本地消息表+MQ

    执行步骤:

    1. A 系统在自己本地一个事务里操作同时,插入一条数据到消息表;
    2. 接着 A 系统将这个消息发送到 MQ 中去;
    3. B 系统接收到消息之后,在一个事务里,往自己本地消息表里插入一条数据,同时执行其他的业务操作,如果这个消息已经被处理过了,那么此时这个事务会回滚,这样保证不会重复处理消息;
    4. B 系统执行成功之后,就会更新自己本地消息表的状态以及 A 系统消息表的状态;
    5. 如果 B 系统处理失败了,那么就不会更新消息表状态,那么此时 A 系统会定时扫描自己的消息表,如果有未处理的消息,会再次发送到 MQ 中去,让 B 再次处理;
    6. 这个方案保证了最终一致性,哪怕 B 事务失败了,但是 A 会不断重发消息,直到 B 那边成功为止。

    注意事项:

    1.严重依赖于数据库的消息表来管理事务,高并发场景下,mysql会是个瓶颈 

    2.本地消息队列是 BASE 理论,是最终一致模型,适用于对一致性要求不高的。实现这个模型时需要注意重试的幂等

    五、第五种方案:可靠消息最终一致性方案

    抛弃本地的消息表,直接基于 MQ 来实现事务。比如阿里的 RocketMQ 就支持消息事务。
    消息队列 RocketMQ 事务消息交互流程如下所示:

    其中:

    1. 发送方向消息队列 RocketMQ 服务端发送消息。
    2. 服务端将消息持久化成功之后,向发送方 ACK 确认消息已经发送成功,此时消息为半消息。
    3. 发送方开始执行本地事务逻辑。
    4. 发送方根据本地事务执行结果向服务端提交二次确认(Commit 或是 Rollback),服务端收到 Commit 状态则将半消息标记为可投递,订阅方最终将收到该消息;服务端收到 Rollback 状态则删除半消息,订阅方将不会接受该消息。
    5. 在断网或者是应用重启的特殊情况下,上述步骤 4 提交的二次确认最终未到达服务端,经过固定时间后服务端将对该消息发起消息回查。
    6. 发送方收到消息回查后,需要检查对应消息的本地事务执行的最终结果。
    7. 发送方根据检查得到的本地事务的最终状态再次提交二次确认,服务端仍按照步骤 4 对半消息进行操作。

    说明:事务消息发送对应步骤 1、2、3、4,事务消息回查对应步骤 5、6、7。 

    六、第六种方案:最大努力通知方案

    这个方案的大致意思就是:

    1.系统 A 本地事务执行完之后,发送个消息到 MQ;
    2.这里会有个专门消费 MQ 的最大努力通知服务,这个服务会消费 MQ 然后写入数据库中记录下来,或者是放入个内存队列也可以,接着调用系统 B 的接口;
    3.要是系统 B 执行成功就 ok 了;要是系统 B 执行失败了,那么最大努力通知服务就定时尝试重新调用系统 B,反复 N 次,最后还是不行就放弃。

    其实,RocketMQ 的消息重试,符合这个解释

  • 相关阅读:
    【Java学习】01. Java基本介绍及环境搭建
    vue组件之间的传值
    检测上传的文件类型js实现方式
    正则表达式学习笔记
    Nuxt.js学习笔记
    Vue+typescript+vuex项目实践学习笔记
    项目依赖&开发依赖
    vuex学习笔记
    export与export default的区别
    ES6 数组去重方法
  • 原文地址:https://www.cnblogs.com/756623607-zhang/p/11028583.html
Copyright © 2011-2022 走看看