一、什么是事务
要么都成功,要么都失败
1. 本地事务
用关系型数据库控制事务,基于关系型数据库的事务被称为本地事务。
数据库事务的四大特性ACID
- A:原子性
- C:一致性
- I:隔离性,多线程操作数据库,并发的事务操作互不干扰,避免脏读、重复读
- D:持久性,事务完成后,数据的更改持久化到数据库,不会被回滚。
2. 分布式事务
多服务远程协作,由于网络问题就会导致分布式事务问题。
2.1 分布式事务产生的场景
a) 微服务架构
b) 单体系统访问多个数据库实例
跨数据库实例产生分布式事务
c) 多服务访问同一个数据库实例
以上均为产生分布式事务的典型场景。
二、分布式事务的基础理论
1. CAP理论
- C:一致性
- A:可用性
-
P:分区容忍性
2. BASE理论
三、分布式事务的解决方案
1. 两阶段提交2PC
1.1 什么是2PC
2PC将事务流程分为两个阶段:准备阶段P、提交阶段C
1.2 2PC解决方案
a) XA方案
b) Seata方案
TM是通知方,TC是执行者
2. TCC
2.1 什么是TCC
Try成功就confirm或人工接入处理
Try失败就cancel
confirm和cancel失败需要重试,保证幂等性
2.2 TCC的解决方案
幂等:一个功能无论执行多少次,效果是一样的
3. 可靠消息最终一致性
3.1 什么是可靠消息最终一致性事务
可靠消息最终一致性方案是指当事务发起方执行完成本地事务后并发出一条消息,事务参与方(消息消费者)一定能够接受消息并处理事务成功,此方案强调的是只要消息发给事务参与方最终事务达成一致。
1. 本地事务与消息发送的原子性问题
2. 事务参与方一定要接收到消息
如果没有收到,重发机制
3. 消息重复消费的问题
由于网络的原因,某个消费节点超时但消费成功,此时消息中间件会重复投递此消息,就导致了消息的重复消费。
要解决消息重复消费的问题就是要实现事务参与方的方法幂等性。
3.2 可靠消息最终一致性解决方案
1. 本地消息表方案
数据库端需要定时扫描消息表,性能开销会比较大。
2. RocketMQ事务消息方案
4. 最大努力通知
4.1 什么是最大努力通知
a) 目标
发起通知方通过一定的机制最大努力将业务处理结果通知到接收方。
- 有一定的消息重复通知机制
- 消息校对机制:如果尽最大努力也没有通知到接收方,或者接收方消费消息后要再次消费,此时可由接收方主动向通知方查询消息信息来满足需求。
b)最大努力通知与可靠消息一致性
可靠消息一致性:发起方保证可靠性,关注交易过程,消息从发出到接收的一致性。
最大努力通知:接收方保证可靠性,用于交易后的通知事务,只提供消息接收的可靠性机制。
4.2 最大努力通知解决方案
a) 方案一
b) 方案二
三、总结
分布式事务对比分析:
- 2PC
最大的诟病是一个阻塞协议,RM在执行分支事务后需要等待TM的决定,此时服务会阻塞并锁定资源。由于其阻塞机制和最差时间复杂度高,因此,这种设计不能适应随着事务涉及的服务数量增加而扩展的需要,很难用于并发较高以及子事务生命周期较长(long-running transactions)的分布式服务中。 - TCC
2PC通常都是在跨库的DB层面,而TCC则在应用层面的处理,需要通过业务逻辑来实现。这种分布式事务的实现方式的优势在于,可以让应用自己定义数据操作的粒度,使得降低锁冲突、提高吞吐量成为可能。而不足之处在于对应用的侵入性非常强,业务逻辑的每个分支都要实现try、confirm、cancel三个操作,实现难度大,需要安装网络状态、系统故障等不同的失败原因实现不同的回滚策略。典型场景:登录送优惠券等。 - 可靠消息最终一致性
可靠消息最终一致性事务适合执行周期长且实时性要求不高的场景,引入消息机制后,同步的事务操作变为基于消息执行的异步操作,避免了分布式事务中的同步阻塞操作的影响,并实现了两个服务的解耦。典型的使用场景:注册送积分、登录送优惠券等。 - 最大努力通知
最大努力通知是分布式事务中要求最低的一种,适用于一些最终一致性时间敏感度低的业务,允许发起通知方处理业务失败,在接收通知方收到通知后积极进行失败处理,无论发起通知方如何处理结果都不影响到接收通知方的后续处理;发起通知方需提供查询执行情况接口,用于接收通知方校对结果。典型场景:银行通知、支付结果通知等。