分布式事务

分布式事务概述

分布式事务是指分布式架构中多个服务节点的数据的一致性。

比如用户下单付完钱之后,即创建订单。仓库接到用户订单开始进行配货处理,扣减库存,这个时候库存这边相对应的显示需要原有的基础上减少。但如果订单没有及时支付,那么库存这边减少的就需要回滚数据。又或者说订单创建失败了,但是库存减少了,这样就导致了数据的不一致。单数据源主要依赖单机事务来保证的,而多数据源下数据的一致性就要依赖分布式事务

CAP原理

  • C:一致性被称为原子对象,任何的读写都应该看起来是“原子“的,或串行的。写后面的读一定能读到前面写的内容。所有的读写请求都好像被全局排序
  • A:对任何非失败节点都应该在有限时间内给出请求的回应。(请求的可终止性)
  • P:允许节点之间丢失任意多的消息,当网络分区发生时,节点之间的消息可能会完全丢失

ACID原理与BASE原理

1. ACID原理:
数据库事务的四大特性,分别是原子性、一致性、隔离性和持久性,简称为ACID

  • 原子性是指一个事务是一个不可分割的工作单位,其中的操作要么都做,要么都不做。
  • 一致性是指事务执行结束后,数据库的完整性约束没有被破坏,事务执行的前后都是合法的数据状态。
  • 隔离性是指,事务内部的操作与其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
  • 持久性是指事务一旦提交,它对数据库的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

2. BASE原理:
BASE主要分基本可用丶软状态丶最终一致性三要素

  • 基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性。
  • 弱状态也称为软状态,指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性。
  • 最终一致性强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。

由分库分表引发的事务问题

单体数据库:

  • 所有的业务表都在同一个数据内
  • 数据库的事务可以很好的得到支持

多数据库:

  • 业务拆分多个数据库
  • 多个独立数据库,事务无法统一
  • 有可能造成数据不一致
    示意图:
    在这里插入图片描述
    比如以上场景,用户使用积分换购商品
    用户库:扣减积分
    订单库:生成订单
    商品库:扣减库存
    都不在同一数据库,不能保证事务统一

分布式事务解决方案

基于XA协议的两阶段提交

一阶段提交:
在这里插入图片描述

  • 事务管理器通知参与该事务的各个资源管理器,通知他们开始准备事务。
  • 资源管理器接收到消息后开始准备阶段,写好事务日志并执行事务,但不提交,然后将是否就绪的消息返回给事务管理器。

总结:应用程序发出提交/回滚请求后,数据库执行操作,而后将成功/失败返回给应用程序,程序继续执行。相对简单暴力,无法协调多数据源。

二阶段提交:
在这里插入图片描述

  • 事务管理器在接受各个消息后,开始分析,如果有任意其一失败,则发送回滚命令,否则发送提交命令。
  • 各个资源管理器接收到命令后,执行(耗时很少),并将提交消息返回给事务管理器。

总结:可以进行事务管理,但容易阻塞,如果其中一个或多个一直不返回消息,则事务管理器一直等待,应用程序也被阻塞,甚至可能永久阻塞下去

事务补偿机制

分段式事务一般做法就是把需求任务分段式地完成,通过事务补偿机制来保证业务最终执行成功,补偿机制分两种:

  1. 定时任务补偿:
    通过定时任务去跟进后续任务,根据不同的状态表确定下一步的操作,从而保证业务最终执行成功
  2. 消息补偿:
    通过实时消息通知下一段任务开始执行,执行完毕后的消息回发通知来保证业务最终完成

补偿机制以后有机会再说,只简单提一下。

基于本地消息表的最终一致方案

听名字就知道了,就是在数据库中建立一张消息表,这张消息表维护执行的事务状态信息。
比如:积分换购商品:

  • 当扣除积分的时候,需要在扣除积分的服务器上新增加一个本地消息表,把需要扣除的积分和减去商品的库存写入到本地消息表,放入同一个事务(依靠数据库本地事务保证一致性)。

  • 这个时候有个定时任务去轮询这个本地事务表,把没有发送的消息,扔给商品库存服务器,让它减去商品的库存。到达商品服务器之后,这时得先写入这个服务器的事务表,然后进行扣减,扣减成功后,更新事务表中的状态。

  • 商品服务器通过定时任务扫描消息表或者直接通知扣除积分服务器,扣除积分服务器在本地消息表进行状态更新。

  • 针对一些异常情况,定时扫描未成功处理的消息,进行重新发送,在商品服务器接到消息之后,首先判断是否是重复的。

  • 如果已经接收,再判断是否执行,如果执行在马上又进行通知事务;如果未执行,需要重新执行由业务保证幂等,也就是不会多扣商品。

总结:基于BASE理论实现,保证了最终一致性,哪怕 B 事务失败了,但是 A 会不断重发消息,直到 B 那边成功为止。不适应高并发场景,而且由于消息会重复投递,需要实现幂等性(防止重复消息数据的处理,一次用户操作,只对应一次数据处理)

基于MQ消息队列的最终一致方案

这里以RabbitMQ为例
不同点:

  • 本地消息表改为MQ
  • 定时任务改为MQ的消费者

注意:使用消息队列后会使系统更为复杂,业务需要考虑的地方更多,人力投入成本也会随之增加。

核心概念:

  • Queue: 真正存储数据的地方
  • Exchange: 接收请求,转存数据
  • Bind: 收到请求后存储到哪里
  • 消息生产者:发送数据的应用
  • 消息消费者: 取出数据处理的应用

使用MQ会遇到的问题:
ACK:
1:消息发送Ack。这种是用来确认生产者将消息发送给交换器,交换器传递给队列的过程中,消息是否成功投递。发送确认分为两步骤: 一是确认是否到达交换器,二是确认是否到达队列。

2:消费者消费Ack。这种是确认消费者是否成功消费了队列中的消息。 (这里包含消息的重回队列及异常重试)

这篇博客都只是一些理论性的东西,后续等有具体实现的Demo再重新发布博客

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值