分布式事务的几种解决方案

x33g5p2x  于2021-06-20 转载在 Java  
字(1.6k)|赞(0)|评价(0)|浏览(654)

分布式事务的四种解决方案

分布式事务指事务的操作位于不同的结点上,需要保证事务的AICD特性。

例如在下单场景下,库存和订单如果不在同一个结点上,就涉及到分布式事务了。

解决方案

1.两阶段提交(2PC)

通过引入协调者Coordinator来协调参与者的行为,并最终决定这些参与者是否要真正执行事务。

1.运行过程

1.1准备阶段

协调者询问参与者事务是否执行成功,参与者发送事务的执行结果给协调者。这个时候参与者执行了事务,但是还没有提交。

1.2提交阶段

如果事务在每个参与者上都执行成功,协调者发送通知让参与者提交事务,如果失败,则发送通知回滚事务。

2.存在的问题

  1. 同步阻塞的,所有事务参与者在等待其他参与者响应的时候都是同步阻塞状态,无法做其他操作
  2. 单点问题,需要保证协调者的高可用,发生故障会造成很大的影响,特别是在第二个阶段,如果发生故障,所有参与者会一直等待,无法做其他操作
  3. 数据不一致的问题,协调者和参与者之间发送消息是通过网络,这个时候网络出现问题,或者抖动,那么只有部分参与者收到执行结果,也就是部分参与者提交了事务,使得系统数据不一致。
  4. 保守,任意一个节点失败就导致整个事务失败,没有完善的容错机制。

3.实现方式

目前支付宝使用两阶段提交思想实现了分布式事务服务 (Distributed Transaction Service, DTS) ,它是一个分布式事务框架,用来保障在大规模分布式环境下事务的最终一致性。具体可看文档:

分布式事务服务DTS

2.补偿事务(TCC)

核心思想是:针对每个操作,都要注册一个与其对应的确认和补偿操作,它分为三个阶段:

  1. try 阶段主要是对业务系统做检测及资源预留,比如订单和存储操作,需要检查库存剩余数量是否够用,并进行预留,预留操作的话就是新建一个可用库存数量字段,Try 阶段操作是对这个可用库存数量进行操作。
  2. confirm 阶段主要是对业务系统做确认提交,try阶段执行成功,并开始执行confirm阶段时,默认confirm阶段是一定成功的。
  3. cancel阶段主要是在业务执行错误,需要回滚的状态下执行的业务取消,预留资源释放。

优点:

  1. 跟2PC比起来,实现和流程相对简单了一些,但是数据的一致性比2PC要差一些。
  2. 解决了协调者单点问题,由主业务方发起并完成这个业务活动
  3. 引入超时后进行补偿,不会锁定整个资源,将资源转换为业务逻辑形式,粒度变小
  4. 数据一致性,有了补偿机制后,由业务活动管理器控制一致性

缺点:在2,3步都有可能失败。TCC属于应用层的一种补偿方式,基于 TCC 实现分布式事务,会将原来只需要一个接口就可以实现的逻辑拆分为 Try、Confirm、Cancel 三个接口,所以代码实现复杂度相对较高,需要程序员在实现的时候自己写很多补偿的代码。

实现:需要事务接口提供 try, confirm, cancel 三个接口,提高了编程的复杂性。依赖于业务方来配合提供这样的接口,推行难度大,所以一般不推荐使用这种方式。

3.本地消息表

本地消息表与业务数据表处于同一个数据库中,这样就能利用本地事务来保证对这两个表的操作满足事务特性,并且使用了消息队列来保证最终一致性。

  1. 在分布式事务操作的一方完成写业务数据的操作之后向本地消息表发送一个消息,本地事务能保证这个消息一定会被写入本地消息表中。
  2. 之后将本地消息表中的消息转发到 Kafka 等消息队列中,如果转发成功则将消息从本地消息表中删除,否则继续重新转发。
  3. 在分布式事务操作的另一方从消息队列中读取一个消息,并执行消息中的操作。

优点: 一种非常经典的实现,避免了分布式事务,实现了最终一致性。

缺点: 消息表会耦合到业务系统中,如果没有封装好的解决方案,会有很多杂活需要处理。

4.MQ事务消息

如果是用的RocketMQ的话,是支持事务消息的,他们的方式也是类似于采用的二阶段提交,但是市面上一些主流的MQ都是不支持事务消息的,比如 RabbitMQ 和 Kafka 都不支持。

参考文章:

分布式事务的自动解决方案

分布式事务,这一篇就够了

相关文章