常见分布式事务解决方案

一、分布式事务开源框架方案

市面上有很多开源的分布式事务框架,下面列举几个!!!

  • seata,seata基本实现了最常用的各个场景的分布式事务解决方案,主要分为以下四种模式
    • XA模式
      • 参考:Seata XA 模式
      • 缺点:需要数据库支持XA协议,长事务,持久占用资源,效率较低(分支事务需要在第二阶段执行后才进行提交或回滚)
      • 优点:强一致性保证,不会有分布式事务的脏读、脏写发生
    • saga模式
      • 参考:SEATA Saga 模式
      • Saga模式是SEATA提供的长事务解决方案,在Saga模式中,业务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务都由业务开发实现。
      • 适用场景
        • 业务流程长、业务流程多
        • 参与者包含其它公司或遗留系统服务,无法提供 TCC 模式要求的三个接口
      • 优点:
        • 一阶段提交本地事务,无锁,高性能
        • 事件驱动架构,参与者可异步执行,高吞吐
        • 补偿服务易于实现
      • 缺点:不保证隔离性
    • TCC模式
      • 参考:Seata TCC 模式
      • 缺点:try、confirm、cancel三个阶段都需要自己做控制,编写起来很麻烦,自己编写的过程中需要注意的点也很多,需要对TCC模式充分了解,业务侵入性很高
      • 优点:灵活性非常高,TCC每个阶段都可以自己控制
    • AT模式
      • 参考:Seata AT 模式
      • 优点:AT模式也是基于2PC思想,但是他在第一阶段执行完后,分支事务就已经提交了,而不用等到第二阶段执行后再提交分支事务,解决了XA模式的持久占用数据库资源的重大缺陷。并且业务侵入性非常低
      • 缺点:会有一定的脏读和脏写问题,参考:Seata 事务隔离级别解读
  • XA实现方案
    • 该方案需要数据库支持XA协议(现在主流的数据库都支持XA协议),但是有个致命的缺点就是事务占用时间过长,资源锁定时间过长,性能较低
    • 优点是强一致性保证,不会有分布式事务的脏读、脏写发生
  • Hmily
    • 很小众不是很常用

二、基于本地消息表方案

本地消息表方案其实就是在数据库创建一张表,用来记录需要发送给第三方的消息记录。

以用户注册送积分场景来举例,假设用户注册时首先调用【账号服务】注册一个账号,同时需要调用【积分服务】为该用户增加积分!

①、流程

  • 首先用户填写完基本信息,点击注册按钮进行注册
  • 【账号服务】新增一个账号,同时往数据库的消息表里写入一条增加积分的消息(这两步操作在同一个事务内,保证了原子性),此时就可以提交事务了,表示账号注册成功
  • 启动一个【定时任务】定时的触发去查询消息表中还未发送的消息,按照消息的路由将消息发送给MQ指定的队列
  • 【积分服务】订阅消息队列(采用MQ的ack机制保证消息一定被消费),获取队列中的消息进行执行增加用户积分操作
    常见分布式事务解决方案_第1张图片

②、优缺点分析

1、优点
  • 实现较为简单,仅依赖MQ和定时任务即可
  • 消息一定不会丢失,安全性较好(由于消息已经持久化到DB的消息表,所以不怕消息丢失,即使将MQ换做Redis的队列也可以)
2、缺点
  • 消息接收方需要自己做幂等控制
  • 基于定时任务轮询,增加积分实时性不高
  • 一般不能回滚,一旦写入本地消息表成功了,则调用方的事务就提交了,如果被调用方执行消息消费时发现需要回滚调用方的事务,这是无法做到的,除非人工介入
  • 基于定时任务轮询频率不好控制,并且将压力放到了DB,在DB压力大的情况下这个选择不是很好

三、基于rocketmq事务消息方案

①、流程

1、生产者向broker发送half消息(half消息并不会被立即投入到目标队列,而是先防止到一个特殊的topic队列中)

2、broker回复half消息是否成功接收

3、根据broker回复的half消息状态决定是否调用本地事务方法

  • 如果half消息发送失败,则不执行本地事务
  • 如果half消息发送成功,则开始执行本地事务

4、本地事务方法调用完毕后,根据本地事务方法的执行结果向broker发送 提交 或 回滚 或 unknown消息

5、如果是提交或回滚消息,则broker直接提交或回滚(提交后消费者就可以消费该消息了)

6、如果是unknown消息,则broker会定时回查本地事务的状态(默认1一分钟一次,最大回查15次,超过15次则默认丢弃该消息)

7、broker根据回查状态来决定是否提交、回滚或丢弃该消息

  • 这里防止超过最大回查次数broker仍然没有得到commitrollback响应导致该消息丢失,我们可以采用【补偿措施】将超过重试阈值的消息存放到DB表里,然后由定时任务或人工处理这些超过重试阈值的消息

8、当本地消息被正常提交后,half消息被转移到目标队列,此时消费方就可以消费该消息进行处理了

常见分布式事务解决方案_第2张图片

②、优缺点分析

1、优点
  • 可适用于转账、注册送积分等不需要事务实时性太高的场景
  • 消息的可靠性由消息发送方保证,消息发送方保证一定能将消息发送给消息接收方(由rocketMq的事务消息来保证消息发送与本地事务同时成功和失败)
2、缺点
  • 不能回滚,一旦消息发出,消息接收方一定要处理这个消息
  • 由于消息可能重复消费,消费方需要保证幂等性

你可能感兴趣的:(架构知识,分布式,java,微服务)