# 消息队列解决分布式事务

消息队列解决分布式事务

  1. 本地消息表:通常处于同一张数据表,通过事务触发器就能实现,但无法解决两张表处于不同的数据库问题

    begin transaction:
    update User set account = account - 100 where userId = 'A'
    insert into message(userId,amount,status) values('A',100,1)
    commit transaction
    
  2. 分布式事务-两阶段提交消息:

    • 基本原理:通过TC事务协调器,分别去确认A,B,C事务的发生,全部成功则使用TC进行提交,否则的话则进行abort

    • 缺点:涉及多次节点提交,通信时间太长;锁定的资源也变得更多。

      2.prepare
      2.prepare
      1.start
      3.yes
      3.yes
      4.commit
      4.commit
      TC事务触发器
      A
      B
      Client
  3. 分布式事务 - 业务方自己实现(使用消息队列来避免分布式事务),例子:B事务伴随着A事务的发生

    • 基本原理:将创建事务和发布事务分成两步操作,创建事务A会在本地数据库存入消息数据库M进行记录,而并不发送消息至B;

      当A事务完成时,再将M发送至B;

      B中通过M_Apply表查找这一消息是否已经操作,未操作则触发操作,或者抛弃;

      B事务完成后,将消息发送至A,A再在库里面删除M表;

      即需要存在的表有:要执行的A表和B表,M表(存储A的事务消息发起,存在于A数据库)和M_apply(校验M消息,存在于B数据库)

      //表M的存在是实现业务与消息的耦合与解耦
      begin transaction
      update A
      set amout=amount - 1000
      where userid=1
      insert into message(userid,amount,status) values (1,1000,1)
      end transaction
      commit;
      //表M_apply的存在解决消息的重复提交
      for each msg in queue
      begin transaction 
      select count(*) as cnf from message_apply where msg_id=msg.msg_id;
      if cnt==0 then
      update B
      set amount = amount + 10000;
      where userId =1;
      insert into mssage_apply(msg_id) values (msg.msg_id);
      //如果应用则将m中数据的id插入mssage_apply
      end transaction1
      commit
      

      缺点:需要设计DB消息表,同时还需要一个后台任务,不断扫描本地消息。导致消息的处理和业务逻辑耦合额外增加业务方的负担。

  4. 分布式事务 - RocketMQ 事务消息

    • 基本原理:
      1. 事务发起方首先发送 prepare 消息到 MQ。
      2. 在发送 prepare 消息成功后执行本地事务。
      3. 根据本地事务执行结果返回 commit 或者是 rollback。
      4. 如果消息是 rollback,MQ 将删除该 prepare 消息不进行下发,如果是 commit 消息,MQ 将会把这个消息发送给 consumer 端。
      5. 如果执行本地事务过程中,执行端挂掉,或者超时,MQ 将会不停的询问其同组的其他 producer 来获取状态。
      6. Consumer 端的消费成功机制有 MQ 保证
  5. 如果事务消息不能够解决以上存在的问题,比如发送端发送成功但接受端一直失败,此时状态下,应当使用人工介入进行回滚。但回滚代价巨大,应尽量避免。

  6. 目前较多的分布式事务解决方案:

    • 结合MQ消息中间件实现可靠传输(目前电商最为流行的方式)

    • TCC补偿性事务解决方案

    • 最大努力通知型方案

      ​ 第一种方案:可靠消息最终一致性,需要业务系统结合MQ消息中间件实现,在实现过程中需要保证消息的成功发送及成功消费。即需要通过业务系统控制MQ的消息状态
      ​ 第二种方案:TCC补偿性,分为三个阶段TRYING-CONFIRMING-CANCELING。每个阶段做不同的处理.

      ​ TRYING阶段主要是对业务系统进行检测及资源预留
      ​ CONFIRMING阶段是做业务提交,通过TRYING阶段执行成功后,再执行该阶段。默认如果TRYING阶段执行成功,CONFIRMING就一定能成功。
      ​ CANCELING阶段是回对业务做回滚,在TRYING阶段中,如果存在分支事务TRYING失败,则需要调用CANCELING将已预留的资源进行释放。
      ​ 第三种方案:最大努力通知xing型,这种方案主要用在与第三方系统通讯时,比如:调用微信或支付宝支付后的支付结果通知。这种方案也是结合MQ进行实现,例如:通过MQ发送http请求,设置最大通知次数。达到通知次数后即不再通知。

  7. 主流的开源MQ(ActiveMQ、RabbitMQ、Kafka、redis)RocketMQ(alibaba)

猜你喜欢

转载自blog.csdn.net/sinat_20744625/article/details/85159337
今日推荐