分布式事务的概念理论
事务
具备以下四个基本特性(ACID)
原子性(Atomicity):一系列操作作被看作一个整体,要么全部成功,要么全部失败
一致性(consistency):如果把所有参与者的数据看成是一个数据集,那么操作前后,数据的总量是不增不减的。也可以理解成数据是满足完整约束的。举例:一个数据集中只有两个参与者A&B,A持有100元,B持有0元,总额100元;A对B转账50元,余额50,B收到50,余额50,金额总量仍然是100,这就是一致性
隔离性(Isolation):事务内部的数据对其它事务是不可见的,这也是对原子性的补充。原子性把系列操作看作一个操作,那么内部操作是不可见的
持久性(Durability):一个事务完成之后数据被永远保存下来,其它操作和故障都不会对事务的结果产生影响
分布式事务
分布式事务是指事务的参与者,支持事务的服务器,资源服务器以及事务管理器分别位于不同的系统之中
也就是说,需要在不同的数据库之间实现事务
带来的挑战:
多个子系统独立,那么多个子系统所构成的大系统,导致了大系统的管理者也就是事务协调器外置,增加了一致性的难度
网络的不稳定性
一致性的划分
强一致性:任何一次读都能都到最新的数据,系统中的所有参与者,看到的操作顺序,都和全局时钟下的顺序一致。简而言之,在任意时刻,所有节点中的数据是一致的
弱一致性:数据更新后,如果能容忍后续的访问只能访问到部分或者全部访问不到,则是弱一致性
最终一致性:不保证在任意时刻任意节点上的同一份数据都是相同的,但是随着事件的迁移,不同节点上的同一份数据总是在向趋同的方向变化。简单说,就是在一段时间后,节点间的数据会最终达到一致性
弱一致性和最终一致性比较容易混淆,比较下区别:
弱一致性,指的是数据更新后,其它参与者并不会马上访问到,访问到的是历史数据,但是从访问的时间线来看,每次访问到的结果都是顺序的,所以也叫顺序一致性
最终一致性,指的是在一定的时间之后,访问到的结果是一样的,假如中间经过了N次操作,但是可能先访问到了之后的操作结果,然后再访问到之前的操作,但是经过一定的时间之后,访问到的数据是最新的
从这点来看,InnoDB实现的可重复读隔离级别就是弱一致性,通过MVCC实现快照读,读取到的不是最新数据,而是历史的某个快照
Zookeeper实现的zab协议,因为允许半数节点成功则提交,那么连接点失败节点的客户端读取到的也是历史数据,所以也叫顺序一致性
CAP原则
CAP分别指 Consistency(一致性),Avaliabity(可用性),Partition tolerance(分区容错性)
CAP原则的内容是:在一个分布式系统中,CAP不能同时满足
另外,这里的一致性指的是,在分布式系统中的所有数据备份,在同一时刻是否相同,也就是强一致性
CAP中,主要是C和A不能同时满足,即不能满足强一致性的情况下,还能满足可用性
证明CA不能同时满足
数据同步过程中,出现了网络无法访问,或者宕机的情况
此时只有两种方式: 要么阻塞等待网络或服务恢复之后,再同步,保证一致性
要么允许客户端访问到历史数据,保证可用性
BASE理论
BASE理论指的是基本可用Basically Avaliable,软状态Soft Stat,最终一致性
核心思想是即便无法做到强一致,但应该采用适合业务场景的方式保证最终一致性
比如:银行转账,A向B发起转账100元,系统首先冻结A账户100元,等待B成功收到100元之后,再将冻结金额扣除
银行转账的双方,都能接受数据的延迟,这就是适合业务场景的方式
分布式事务解决方案的理论模型
XA协议包含:
- 两阶段提交2PC
- 三阶段提交3PC
3PC在2PC的基础上增加了一个询问阶段和超时机制,避免资源被永久锁定,但仍然存在宕机的问题,导致数据不一致,因此3PC所做的工作有点多余
两阶段XA
2PC的执行分为两个步骤:
Prepare:事务管理器向所有本地资源管理器发起请求,询问是否是ready状态,所有事务都将事务能否成功的信息反馈给协调者,锁住对应的资源
Commit:事务管理器根据所有本地资源管理器的反馈,通知所有本地资源管理器,步调一致地在所有分支上提交或回滚
因此实现XA需要有3个接口,注意,这是在数据库层面的commit,rollBack
1.prepare接口,锁定资源
2.commit接口,提交事务
3.rollBack接口,回滚事务
存在的问题:
1.prepare锁住对用的资源,整个过程时阻塞的
2.事务协调者发生宕机,导致事务不一致
TCC
TCC理论上也是XA协议的一种实现,区别只是讲数据库层的XA提升到了service层
三个角色:事务协调者,事务发起者,事务参与者
TCC需要在Service层实现三个接口
Try阶段,锁定对应的资源
Confirm阶段,确认,提交资源
Cancel阶段,取消,释放资源
XA总结
无论2PC,3PC还是TCC的理论模型可以看到,都无法完全保证事务的一致性
所以实际的上解决方案是XA的变种,但还是基于XA的
实际方案:
在事务协调者中维护一个大事务表,记录状态
在事务协调者中维护一个小事务表,记录每个事务参与者的状态
-
事务协调者通过过定时检查大事务,然后再找到小事务对应的参与者,通过调用XA两阶段的两阶段接口进行补偿,达到最终一致
所以,这也要求两阶段接口具有幂等性
本地消息表
本地消息表方案最初由ebay架构师提出,该方案中涉及消息生产者和消息消费者两个角色
步骤:
1.A业务事务完成时,写入一条消息到本地消息表,记录消息状态是否被成功处理,使用本地事务保证数据一致性,并发送数据到MQ,如果发送MQ失败,则使用定时任务扫描补偿
2.B业务消费MQ,并保证消费的幂等性,如果消费成功,则通知A业务更新消息表状态(可以是回调,也可以是MQ)
3.A业务根据通知消息更新消息状态
分析:
比较适合的场景是下单成功后,短信的发送,邮件的发送
如果是优惠券的发放,可能会出现优惠券不足,则可能会扣减失败,如果使用这种方式,则需要A业务设置一个中间状态,并支持回滚
尽最大努力通知
支付回调就是典型的尽最大努力通知的场景
第三方支付服务,如微信,支付宝,当处理完这笔订单之后,就会发起一个回调通知调用方
如果失败会继续重试,直到达到重试最大次数,然后交由对账系统来处理
分布式事务理论模型总结
从上面的分析可以看到,不同解决方案的理论模型适合不同的业务场景
主要参考:https://xiaomi-info.github.io/2020/01/02/distributed-transaction/