常见分布式事务解决方案

本文介绍了分布式事务的两种经典协议——两阶段提交(2PC)及其缺点,以及TCC补偿模式的工作原理。2PC在协调者故障时可能导致资源长时间锁定和数据不一致。TCC通过Try-Confirm-Cancel三步操作确保事务最终一致性,若出现异常则通过重试机制保证完成。此外,提到了基于可靠消息和本地消息表的最终一致性方案。
摘要由CSDN通过智能技术生成

两阶段提交(2PC, Two-phase Commit)

两阶段提交又称2PC,2PC是一个非常经典的中心化的原子提交协议,这里所说的中心化是指协议中有两类节点:

  1. 中心化协调者节点(coordinator)
  2. N个参与者节点(partcipant)

两个阶段:

  1. 投票阶段
  2. 提交/执行阶段

举例:订单服务需要调用支付服务去支付,支付成功则处理购物订单为待发货状态,否则就需要将购物订单处理成失败状态

第一阶段:投票阶段

在这里插入图片描述

第一阶段主要分为3步:

  1. 事务询问: 协调者向所有的参与者发送事务预处理请求,称之为Prepare,并开始等待各参与者的响应
  2. 执行本地事务: 各个参与者节点执行本地事务操作,但在执行完成后并不会真正提交数据库本地事务, 而是先向协调者报告能否处理
  3. 各参与者向协调者反馈事务询问的响应: 如果参与者成功执行了事务操作,那么就反馈给协调者Yes响应,表示事务可以执行,如果没有参与者 成功执行事务,那么就反馈给协调者NO响应,表示事务步不可以执行

第一阶段执行完后,会有两种可能:

  • 所有都返回Yes(成功流程)
  • 有一个或者多个返回No(异常流程)

第二阶段:提交/执行阶段(成功流程)

前提条件: 所有参与者都返回Yes
在这里插入图片描述
成功流程主要分为两步:

  1. 所有的参与者反馈给协调者的信息都是Yes,那么就会执行事务提交,协调者所有参与者节点发出Commit请求
  2. 事务提交,参与者收到Commit请求之后,就会正式执行本地事务Commit操作,并在完成提交之后释放整个事务执行期间占用的事务资源

第三阶段:提交/执行阶段(异常流程)

前提条件: 有一个或者多个返回No

在这里插入图片描述
异常流程也分为两步

  1. 发送回滚请求,协调者向所有参与者节点发出rollback请求
  2. 事务回滚,参与者接收到rollback请求后,会回滚本地事务

2PC缺点

  1. rollback 请求无论是在第一阶段的过程中,还是在第二阶段,所有的参与者资源和协调者资源都是被锁住的,只有当所有的节点准备完毕,事务协调者才会通知进行全局提交,参与者进行本地事务提交后才会释放资源.这样过程会比较漫长,对性能影响比较大
  2. 单节点故障: 由于协调者的重要性,一旦协调者发生故障.参与者会一直阻塞下去,尤其在第二阶段,协调者发生故障,那么所有参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作(虽然协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致参与者处于阻塞状态的问题)
  3. 数据不一致: 在第二阶段中,当协调者参与者发送commit请求之后,发生了局部网络异常,或者在发送commit请求过程中,协调者发生了故障,这回导致只有一部分参与者接收到了commit请求,而在这部分参与者接到commit请求之后就会执行commit操作,但是其他部分未接到commit请求的节点则无法进行事务提交,于是整个分布式系统便出现了数据不一致的现象

TCC 补偿模式

TCC又称补偿事务,其核心思想是:“针对每个操作都要注册一个与其对应的确认和补偿(撤销)操作”.它分为三个操作:

  • Try阶段: 主要是对业务系统做检测及资源预留。
  • Confirm阶段: 确认执行业务操作
  • Cancel阶段: 取消执行业务操作

Confirm阶段和Cancel阶段是或者的关系.
在这里插入图片描述
一个订单支付之后,我们需要做下面的步骤:

  1. 更改订单的状态为已支付
  2. 扣减商品库存
  3. 给会员增加积分
    在这里插入图片描述
    在这里插入图片描述
    如果库存服务扣减库存失败,直接通知订单服务异常,订单服务撤销修改订单的操作,然后通知积分服务撤销增加积分操作
    如果一切正常就确认执行业务操作

总结

  1. 如果需要使用TCC分布式事务的话,首先需要选择某种TCC分布式事务框架,各个服务就会有这个TCC分布式事务框架在运行
  2. 然后原本的一个接口,要改造为3个逻辑,Try-Confirm-Cancel
    • 先是服务调用链路依次执行Try逻辑
    • 如果都正常的话,TCC分布式事务框架推进Confirm逻辑,完成整个事务
    • 如果某个服务的Try逻辑有问题,TCC分布式事务框架感知到之后就会推进各个服务的Cancel逻辑,撤销之前执行的各种操作
    • 这就是所谓的TCC分布式事务
  3. java中阿里开源的seata是支持TCC模式的,golang中有民间大神开源出来的seata-go也是支持TCC模式的

思考

  • 如果有一些意外情况发生了,比如订单服务突然挂了,然后再次重启,TCC分布式事务框架是如何保证之前没执行完的分布式事务继续执行的呢?
    • TCC事务框架都是要记录一些分布式事务的活动日志的,可以在磁盘的日志文件里记录,也可以在数据库里记录,保存下来分布式事务运行的各个阶段和状态,重启后如果发现有没有执行完的事务,会继续执行的
  • 万一某个Cancel或者Confirm逻辑执行一直失败怎么办?
    • TCC事务框架会通过活动日志记录各个服务的状态,如果某个服务的Cancel或者Confirm一直没成功,会不停的重试调用它的Cancel或者Confirm逻辑,务必要它成功,正常情况下,保证充足的测试,Confirm和Cancel都是可以成功的,如果实在解决不了,也属于一个小概率事件,可以发邮件通知人工处理

基于可靠消息最终一致性方案

目前RocketMQ支持事务消息,以创建订单为例:

  1. 生产者订单系统先发送一条half消息到Broker,half消息对消费者而言是不可见的
  2. 再创建订单,根据创建订单成功与否,向Broker发送commit和rollback
  3. 并且生产者订单系统还可以提供Broker回调接口,当Broker发现一段时间half消息没有收到任何操作命令(即没有commit也没有rollback),则会主动调用此接口来查询订单是否创建成功
  4. 一旦half消息commit了,消费者库存系统就会来消费,如果消费成功,则消息销毁,分布式事务成功结束
  5. 如果消费失败,则根据重试策略进行重试,最后还失败则进入私信队列,等待进一步处理

在这里插入图片描述

基于本地消息表实现最终一致性

以创建订单为例:
创建订单时,将减库存消息加入再本地事务中,一起提交到数据库存入本地消息表,然后调用库存系统,如果调用成功则修改本地消息状态为成功,如果调用库存系统失败,则由后台定时任务从本地消息表中取出未成功的消息,重试调用库存系统

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

.番茄炒蛋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值