引言随着业务量的不断增长,单体架构渐渐扛不住巨大的流量,此时就需要对服务进行 拆分 ,数据库、表做 分库分表 处理 。以订单系统为例,也就产生了订单中心、用户中心、库存中心等,由此带来的问题就是业务间相互隔离,每个业务都维护着自己的数据库,数据的交换只能进行 RPC 调用 。
当用户再次下单时,需同时对订单库 order、库存库 storage、用户库 account 进行操作,可此时我们只能保证自己本地的数据一致性 , 无法保证调用其他服务的操作是否成功,所以为了保证整个下单流程的数据一致性,就需要分布式事务介入 。
文章插图
分布式事务方案一览实现分布式事务的方案比较多,常见的比如基于 XA 协议的 2PC、3PC,基于业务层的 TCC,还有应用消息队列 + 消息表实现的最终一致性方案 。
- 2PC
两阶段提交(2PC) , 对业务侵?很小 , 它最?的优势就是对使??透明 , 用户可以像使?本地事务?样使?基于 XA 协议的分布式事务 , 能够严格保障事务 ACID 特性 。
文章插图
2PC的缺点也是显而易见,它是一个强一致性的同步阻塞协议,事务执?过程中需要将所需资源全部锁定,也就是俗称的 刚性事务 。所以它比较适?于执?时间确定的短事务,整体性能比较差 。
一旦事务协调者宕机或者发生网络抖动 , 会让参与者一直处于锁定资源的状态或者只有一部分参与者提交成功,导致数据的不一致 。因此,在?并发性能?上的场景中,基于 XA 协议的分布式事务并不是最佳选择 。
文章插图
- 3PC
2PC 中只有协调者有超时机制,3PC 在协调者和参与者中都引入了超时机制,协调者出现故障后,参与者就不会一直阻塞 。而且在第一阶段和第二阶段中又插入了一个准备阶段(如下图),保证了在最后提交阶段之前各参与节点的状态是一致的 。
文章插图
虽然 3PC 用超时机制,解决了协调者故障后参与者的阻塞问题 , 但与此同时却多了一次网络通信,性能上反而变得更差,也不太推荐 。
- TCC
以下单扣库存为例,Try 阶段去占库存,Confirm 阶段则实际扣库存,如果库存扣减失败 Cancel 阶段进行回滚,释放库存 。
TCC 不存在资源阻塞的问题,因为每个方法都直接进行事务的提交,一旦出现异常通过则 Cancel 来进行回滚补偿,这也就是常说的补偿性事务 。
原本一个方法,现在却需要三个方法来支持 , 可以看到 TCC 对业务的侵入性很强,而且这种模式并不能很好地被复用,会导致开发量激增 。还要考虑到网络波动等原因,为保证请求一定送达都会有重试机制,所以考虑到接口的幂等性 。
- 消息事务(最终一致性)
下单扣库存原理图:
文章插图
- 订单系统向 MQ 发送一条预备扣减库存消息,MQ 保存预备消息并返回成功 ACK
- 接收到预备消息执行成功 ACK,订单系统执行本地下单操作 , 为防止消息发送成功而本地事务失败,订单系统会实现 MQ 的回调接口,其内不断的检查本地事务是否执行成功 , 如果失败则 rollback 回滚预备消息;成功则对消息进行最终 commit 提交 。
推荐阅读
- 婚礼会场布置策划方案 婚礼会场该怎么选择
- 聊聊接口重试机制的几种解决方案
- 彻底搞透分布式一致性
- 计划与方案的区别 计划与方案的区别是什么
- 意见和方案的区别在哪 意见和方案的区别
- 工作方案和实施方案的区别在哪 工作方案和实施方案的区别
- 使用Ray轻松进行Python分布式计算
- Go的分布式应用:使用Raft算法
- Java中的代码传递行为:解决类膨胀问题的方案
- 长江珍稀鱼类保护方案