1. ACID 特性
- 原子性(Atomicity)
- 一致性(Consistency)
- 隔离性(Isolation)
- 持久性(Durability)
2. 分布式事务问题的理论模型
2.1 X/Open 分布式事务模型
X/Open DTP(X/Open Distributed Transaction Processing Reference Model)是X/Open这个组织定义的一套分布式事务的标准,提出用两阶段提交(2PC,Two-Phase-Commit)来保证分布式事务的完整性。
AP:Application,应用程序
RM:Resource Manager,资源管理器,比如数据库
TM:Transaction Manager,事务管理器,一般指事务协调者。
上图与本地事务的原理基本相同,唯一不同在于,如果此时RM代表数据库,则TM需要能够管理多个数据库的事务,步骤如下:
- 配置TM,把多个RM注册到TM,相当于TM注册RM作为数据源。
- AP从TM管理的RM中获取连接。
- AP向TM发起一个全局事务,生成全局事务ID(XID),XID会通知各个RM。
- AP通过第二步获得的连接直接操作RM完成数据操作(AP每次操作都会传XID给RM)。
- AP结束全局事务,TM会通知各个RM全局事务结束。
- 根据各个RM的事务执行结果,执行提交或者回滚操作。
2.2 两阶段提交协议(2PC)
2.2.1 概念
- 准备阶段:事务管理器(TM)通知资源管理器(RM)准备分支事务,记录事务日志,并告知事务管理器的准备结果。
- 提交/回滚阶段:
- 如果所有的资源管理器(RM)在准备阶段都明确返回成功,则事务管理器(TM)向所有的资源管理器(RM)发起事务提交指令完成数据的变更。
- 反之,如果任何一个资源管理器(RM)明确返回失败,则事务管理器(TM)会向所有资源管理器(RM)发送事务回滚指令。
2.2.2 优缺点
- 优点:充分考虑了分布式系统的不可靠因素,并且采用非常简单的方式就把系统不可靠而导致事务提交失败的概率降到最小。
- 缺点:
- 同步阻塞:所有参与者(RM)都是事务阻塞型的,如果得不到响应占用的资源会一直锁定。
- 过于保守:任何一个节点失败都会导致数据回滚。
- 事务协调者的单点故障:如果协调者第二阶段出现了故障,那么其他参与者(RM)会一直处于锁定状态。
- “脑裂”导致数据不一致:第二阶段,事务协调者向所有参与者(RM)发送commit请求后,发生局部网络异常导致只有一部分参与者(RM)接收了commit请求,导致不一致。
2.3 三阶段提交协议
2.3.1 概念
利用超时机制解决了2PC的同步阻塞问题。
- CanCommit(询问阶段):事务协调者向参与者发送事务执行请求,询问是否可以完成指令,参与者只需要回答是与不是,不需要做真正事务操作,包含超时机制。
- PreCommit(准备阶段):
- 如果询问阶段所有参与者都返回可以执行操作,则事务协调者会向PreCommit请求,参与者收到请求后写redo和undo日志,执行事务操作但是不提交事务,然后返回ACK响应等待事务协调者下一步通知。
- 如果询问阶段有参与者返回不能执行操作,事务协调者向所有参与者发送中断请求。
- DoCommit(提交或回滚阶段):
- 如果参与者在上一阶段都返回成功,事务协调者会向所有参与者发起事务提交指令。
- 如果有参与者返回失败,事务协调者会发起中止指令来回滚事务。
2.3.2 优化点
比起 2PC,有以下不同点:
- 增加一个CanCommit阶段,用于询问所有参与者是否可以执行事务操作并且响应,尽早发现无法执行操作而中止后续的行为。
- 在准备阶段之后,协调者和参与者都引入了超时机制,一旦超时继续提交事务,并且认为处于成功状态,因为这种情况下事务默认为成功的可能性较大。
2.4 CAP 定理和 BASE 理论
2.4.1 CAP 定理
又叫布鲁尔定理,指在分布式系统中不可能同时满足以下三个基本需求,最多只能同时满足两个。
- C - 一致性(Consistency):数据在多个副本中要保持强一致。
- A - 可用性(Availability):系统对外提供的服务必须一直处于可用状态,在任何故障下,客户端都能在合理的时间内获得服务端的非错误响应。
- P - 分区容错性(Partition Tolerance):在分布式系统中遇到任何网络分区故障,系统仍然能够非常对外提供服务。
在分布式系统中,要么满足 CP,要么满足 AP,不可能实现 CAP 或 CA。原因是网络通信并不是绝对可靠的,所以P - 分区容错性是必然要满足的。
如果是CA或CAP的情况,相当于网络百分百可靠,否则当出现网络分区情况时,为了保证数据一致性,必须拒绝客户请求,这样又无法满足A,所以不可能选择CA,只有AP或CP两种选择。
- AP:相当于放弃了强一致性,实现最终的一致,这是很多互联网公司解决分布式数据一致性问题的主要选择。
- CP:放弃高可用性,实现强一致性。两阶段提交和三阶段提交都是这种方案,导致的问题是客户完成一个操作会等待较长的时间。
2.4.2 BASE 理论
- Basically Available(基本可用):分布式系统出现故障时允许损失一部分功能的可用性,保证核心功能的可用。
- Soft State(软状态):允许系统中的数据存在中间状态,这个状态不影响系统的可用性,也就是允许系统中不同节点的数据副本之间的同步存在延时。
- Eventually Consistent(最终一致性):中间状态的数据在经过一段时间之后,会达到一个最终的数据一致性。
3. 常见解决方案
3.1 TCC补偿型方案
3.1.1 概念
TCC(Try-Confirm-Cancel)是一种2PC思想的解决方案,将完整业务拆分为如下三个步骤:
- Try:这个阶段主要是对数据的校验或者资源预留。
- Confirm:确认真正执行的任务,只操作 Try 阶段预留的资源。
- Cancel:取消执行,释放 Try 阶段预留的资源。
3.1.2 注意点
- TCC事务框架会记录一些分布式事务操作日志,保存事务各个阶段和状态,并在出现异常时根据操作日志进行重试,以达到数据的最终一致性。
- TCC服务支持接口调用失败发起重试,所以接口需要满足幂等性。
3.2 基于可靠性消息的最终一致性方案
3.2.1 概念
通过消息中间件的可靠性机制来实现数据一致性的投递。
以支持事务消息模型的消息中间件 RocketMQ 为例,执行过程如下:
- 生产者发送一个事务消息到MQ(消息队列)上,MQ只记录这条消息数据,消费者无法消费;
- 生产者执行具体业务逻辑,完成本地事务的操作;
- 生产者根据本地事务执行结果发送一条确认消息到MQ服务器,本地事务成功者发送Commit消息,表示第一步发送的消息可以消费;否则MQ服务器会删除第一步存储的消息;
- 生产者因为某些情况一直未给MQ服务器发送确认,MQ服务器会定时主动会查生产者获取本地事务的执行结果,根据回查结果决定这条消息是否需要投递给消费者。
- MQ服务器上存储的消息被生产者确认之后,消费者就可以消费,消费完成之后发送一个确认标识给MQ服务器,表示消息投递成功。
3.2.1 特点
-
在 RocketMQ 事务消息模型中,事务是由生产者完成的,消费者不需要考虑。
因为MQ可靠性投递机制的存在,如果消费者没有签收该消息,则MQ服务器会重复投递来实现生产者和消费者本地数据的最终一致性。 -
RocketMQ 事务消息模型中最核心的机制是事务回查。
查询模式在很多其他类似场景都可以使用,比如用来解决服务间调用超时导致的结果未知问题。
3.3 最大努力通知型
3.3.1 概念
和基于可靠性消息的最终一致性方案实现类似,是一种比较简单的柔性事务解决方案,比较适用于对数据一致性要求不高的场景。
典型示例:支付宝支付结果通知。
从商户角度分析最大努力通知型处理过程:
- 商户创建一个支付订单,再调用支付宝发起支付请求;
- 支付宝唤醒支付页面完成支付操作,并针对该商户创建一个支付交易,根据用户的支付结果记录支付状态;
- 支付完成后触发一个回调通知商户,商户收到通知后根据结果修改本地支付订单的状态,并返回一个处理状态给支付宝;
- 针对这个订单,理想状态下支付宝和商户的交易状态会在通知完成后达到最终一致。但由于网络的不确定性,支付结果通知可能失败或丢失,导致商户端的支付订单状态是未知的。这是最大努力通知型起作用,如果商户端在收到支付结果通知后没有返回一个"SUCCESS"状态码,则该支付结果回调请求会以衰减重试机制继续触发,比如1min、5min、10min…直到最大通知次数。
- 对于达到最大通知次数商户还没有返回确认状态的情况,支付宝提供了一个交易结果查询接口,商户可以通过定时器或人工对账方式来查询该接口,根据支付订单号查到支付结果来更新商户的支付订单状态。
4. 分布式事务框架Seata
Spring Cloud Alibaba 体系的一款开源分布式事务解决方案,提供了 AT、TCC、Saga、XA 事务模式。
4.1 AT模式
Seata 主推的一种方案,基于XA演进而来,也是2PC模型,包括TM、RM、TC三大模块。
TM 和 RM 最为 Seata 客户端与业务系统继承, TC 作为 Seata 的服务器独立部署。
- TM:事务管理器(Transaction Manager),负责向TC注册一个全局事务,生成全局唯一的XID;
- RM:资源管理器(Resource Manager),每个数据库资源当作一个RM,业务层面通过JDBC标准的接口访问RM时,Seata会拦截请求。
- TC:事务协调器(Transaction Coordinator),每个本地事务提交时,RM会向TC注册一个分支事务。
执行流程:
- TM 向 TC 注册全局事务,生成全局唯一的 XID;
- RM 向 TC 注册分支事务,并将其纳入该 XID 对应的全局事务范围;
- RM 向 TC 汇报资源的准备状态;
- TC 汇总所有事务参与者的执行状态,决定分布式事务是全部回滚或提交;
- TC 通知所有 RM 提交/回滚事务。
4.2 Saga 模式
4.2.1 概念
又称长事务解决方案,非2PC,把一个业务流程中的长事务拆分为多个本地短事务,业务流程中的每个参与者都提交真实的提交给该本地短事务,但其中一个参与者事务执行失败,则通过补偿机制补偿前面已经成功的的参与者。
和TCC相比,少了 Try 预留动作,每一个操作都真实地影响到数据库。
4.2.2 两种执行方式
Saga由一系列 sub-transaction Ti 组成,每个 Ti 都有对应的补偿动作 Ci,用于撤销 Ti 造成的数据变更结果。
有两种执行方式:
- T1, T2, T3, …, Ti:表示所有事务都正常执行。
- T1, T2, …, Tj, Cj, …, C2, C1 (其中 0<j<i):这种方式表示执行到 Tj 事务时出现异常,通过补偿操作撤销之前所有成功的 sub-trasaction。
4.2.3 两种补偿恢复方式
- 向后恢复:任一事务执行失败,则把之前执行过的结果逐一撤销(即上面第二种执行方式)。
- 向前恢复:不进行补偿,而是对失败事务进行重试,比较适合事务必须执行成功的场景。
两种恢复方式都可能出现失败情况,最坏情况下只能人工干预处理。
4.2.4 优劣势
- 优势:
- 一阶段直接提交本地事务,没有锁等待,性能较高;
- 在事件驱动模式下短事务可异步执行;
- 补偿机制实现比较简单。
- 劣势:
- 不提供原子性和隔离性支持(隔离性影响较大)。
4.2.5 两种协调模式
- 事件 / 编排式:把 Saga 的决策和执行顺序逻辑分布在 Saga 的每一个参与者中,通过交换事件的方式进行沟通。
- 命令 / 协同式:把 Saga 的决策和执行顺序逻辑集中在一个 Saga 控制类(Saga协调器)中,以命令 / 回复方式与每项服务进行通信, 告诉他们应该执行哪些操作。