3.11:分布式事务
本文将梳理微服务架构下,分布式事务的常用方案。整体包含以下三部分:
-
分布式事务的提出
-
分布式事务主流方案
-
分布式事务选择
分布式事务的提出
数据库事务
事务概念
事务一般指数据库事务,数据库事务是访问并可能操作各种数据项的一个 数据库操作序列,这些操作 要么全部执行,要么全部不执行。是一个 不可分割的工作单元。事务由事务开始和事务结束之间的全部数据库操作组成。
ACID特性
-
原子性(Atomicity):事务中的全部操作在数据库中是不可分割的,要么全部执行,要么全部不执行。
-
一致性(Consistency):几个并行执行的事务,其执行结果必须与按某一顺序 串行执行的结果相一致。
-
隔离性(Isolation):事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的。
-
持久性(Durability):对于任意已提交的事务,系统必须保证该事务对数据库的修改不会丢失,即使数据库出现故障。
隔离性
要理解事务隔离性,首先需要了解事务的并发问题:
-
脏读:事务A读取了事务B未提交的数据,然后事务B回滚,那么事务A读取到的数据是脏数据。
-
不可重复的:事务A多次读取同一数据,事务B在事务A多次读取过程中,对数据做了更新并提交,导致事务A多次读取同一数据时,出现不一致性。
-
幻读:事务A在第二次查询时,读到了事务B新提交的数据。
隔离级别 | 脏读 | 不可重复的 | 幻读 |
---|---|---|---|
读未提交 | 是 | 是 | 是 |
不可重复读 | 否 | 是 | 是 |
可重复读 | 否 | 否 | 是 |
串行化 | 否 | 否 | 否 |
分布式事务
场景驱动
微服务架构下,数据分散在多个存储中,此时无法使用传统的数据库事务,就需要分布式事务来保证多个存储的数据一致性。
image分布式事务主流方案
说到分布式场景的问题,基本上都绕不开CAP定理,我们先对CAP定理有个基本的概念。
CAP定理
CAP定理是指,在分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)。这三个要素只能满足其中的两个,不可能三者兼顾。
一般而言分布式事务都是实现多个数据库之间的事务一致性,因此分布式事务要满足的就是CAP定理中的CP,也就是保证网络分区下的强一致性。
但若系统追求强CP,那在出现网络分区时,就必须牺牲系统的可用性。因此基于CP之上,又提出了数据的最终一致性理论,比如Base、Saga等。
分布式事务分类
基于上述理论之上,目前的主流的分布式事务可以分为强一致性和弱一致性(最终一致性)。
- 强一致性(XA模型)
- 2PC
- 3PC
- 弱一致性
- 同步模型
- TCC
- Saga
- 异步模型
- 事务消息
- 本地消息表
- 同步模型
下面我们针对上述的分布式一致性方案逐个详细梳理。
强一致性
强一致性的核心思想是,所有事务在提交/回滚阶段,必须保证成功提交/回滚,也就是多个事务必须是同时提交成功或回滚成功。只要有一个事务未完成提交或回滚,分布式事务都不能结束。
理论模型:XA模型
XA模型主要由三部分组成,事务管理器(TM)、资源管理器(RM)、应用程序(AM)。
-
事务管理器(TM):负责管理全局事务,生成唯一事务ID,监控事务的执行、并负责事务的提交、回滚、失败恢复等。
-
资源管理器(RM):管理计算机共享资源,资源即数据库,真正执行事务的提交、回滚。
-
应用程序(AM):定义事务的边界,并访问事务边界内的资源。
2PC
XA模型只是规范,2PC是基于XA模型的实现。2PC整体分为两个阶段:准备、提交。
第一阶段(准备):
-
事务管理器TM向所有应用程序AP发prepare消息。
-
应用程序AP收到表决请求后,执行本地事务,写redo日志和undo日志,但不提交事务。
-
应用程序AP向事务管理器TM响应结果ACK(提交或回滚)。
若事务管理器TM收到所有的ACK都是OK,则进行第二阶段的事务提交,只要有一个ACK是NO,则进行第二阶段的回滚。
第二阶段(提交)
-
事务管理器TM向所有的应用程序AP发送事务提交(commit)请求。
-
应用程序收到提交请求后,读取redo日志,完成本地事务的提交。
-
应用程序AP向事务管理器TM响应提交结果。
第二阶段(回滚)
-
事务管理器TM向所有的应用程序AP发送事务提交(rollback)请求。
-
应用程序收到提交请求后,读取undo日志,完成本地事务的回滚。
-
应用程序AP向事务管理器TM响应回滚结果。
注意:在第二阶段执行中是不可逆的,要求所有事务都必须完成提交或回滚,若提交或回滚失败,本地事务需重新恢复继续提交或回滚,直到成功为止。
2PC主要有如下两个较大的缺点:
-
同步阻塞过长,整个分布式事务执行过程中所有AP都是同步等待的。
-
TM单点问题,若当AP即将进入第二阶段时,TM故障,AP将一直等待阶段,无法进入commit。
3PC
3PC是在2PC基础上,将2PC的第一阶段拆分为两个阶段,是2PC的改进版。
第一阶段(canCommit)
-
事务管理器TM向所有的应用程序AP发送canCommit消息。
-
应用程序收到canCommit请求后,检查本地事务链接、权限等,确定是否可以执行事务。
-
应用程序AP向事务管理器TM响应检查结果。
若事务管理器TM收到所有的应用程序AP的canCommit响应都是OK,则进入第二阶段,否则直接取消分布式事务。
第二阶段(preCommit)
-
事务管理器TM向所有应用程序AP发preCommit消息。
-
应用程序AP收到表决请求后,执行本地事务,写redo日志和undo日志,但不提交事务。
-
应用程序AP向事务管理器TM响应结果ACK(提交或回滚)。
第三阶段,与2PC的第二阶段是一样的,就不再累述。
3PC相较2PC主要有两个改进,减少阻塞(增加了canComit),应用程序增加了超时自动commit。但同步性能问题仍然未解决。
弱一致性(最终一致性)
弱一致性的核心思想是,将一个分布式事务拆分为多个本地事务,若在本地事务执行过程中出现异常,则执行补偿来保证数据能最终一致。
弱一致性根据事务的执行方式,又可以分为同步模型和异步模型。同步是指多个事务执行是同步的,也就是由同一个线程来协调/编排事务提交。异步是指每个事务的提交和补偿是由本地事务自己来完成的。
同步模型
目前常用的同步模型主要是TCC和Saga。
TCC
TCC核心思想是,先对所需资源进行锁定或申请,若锁定成功,则执行提交,若锁定失败则对锁定资源进行释放。
TCC模型要求所有应用程序都要实现try、confirm、cancle三个方法:
-
try:提供对资源的锁定,预留资源、数据锁定等。
-
confirm:在try成功后,调用该方法完成业务逻辑的处理。
-
cancle:若try失败时,需要对已经完成try的事务进行补偿,也就是释放预留和锁定的资源。
关于TCC服务器故障时:
-
若在try过程中有部分机器故障,协调器需要根据记录的已执行try的事务,并调相应的cancle方法完成资源释放。
-
若confirm、cancle阶段有机器故障,协调性不断的重新发起confirm、cancle的调用。
Saga
Saga将分布式事务拆分为一系列的本地事务T1,T2,T3,...,Tn,每个本地事务提供相应的补偿动作C1,C2,C3,...,Cn. Saga保证分布式事务执行顺序为:
-
T1,T2,T3,...,Tn
-
T1,T2,T3,...,Tj,Cj-1,...,C1
同时,Saga定义了两种恢复策略:
-
向后恢复:补偿所有已完成的事务。
-
向前恢复:假设所有事务最终都会成功,不断重试失败的事务,这种情况下是不需要C的。
业务中基本上使用的都是T1,T2,T3,...,Tj,Cj-1,...,C1的执行顺序。
image异步模型
异步模型即为将分布式事务下的服务同步调用异步化,比如原有的调用为A->B->C,异步化后为:业务调用->A->MQ,MQ->B->MQ,MQ->C。
异步化后,只需要保证MQ消息的可靠性,也就是说需要保证本地事务执行成功后MQ一定能发送成功。
消息的可靠性可借助事务消息组件和本地消息表。
事务消息(RocketMQ)
RocketMQ相较于其他MQ主要有以下改进来保证消息的可靠传递:
-
支持“半消息”,业务方(生产者)在执行本地事务前,需先向RocketMQ发送“半消息”,此时的消息处于“暂不投递”状态,需要业务方(生产者)在执行完本地事务后发送二次确认才进行投递。
-
业务提供消息“回查”功能,为了防止业务方(生产者)在发送“半消息”后系统故障,RocketMQ会对长期处于“暂不投递”状态的消息,调用业务方(生产者)提供回查接口来决定是否投递。
-
“消费者”在消息重复发送时需要保证幂等性。
本地消息表
事务消息的缺点是,目前只有RocketMQ支持事务消息,对技术选型有限制。因此,基于事务消息来改造,将消息和业务数据表的强一致性使用本地事务来保证。
-
在业务服务数据库中创建消息表,将业务和消息保存放到同一个本地事务中。
-
基于业务服务数据库启动独立的msgClient,不断轮询消息表,将本地消息表中未发送成功(待发送、发送失败、发送超时)的消息发送给MQ组件。
-
对发送成功(接收到ACK响应)的消息进行删除,
-
“消费者”在消息重复发送时需要保证幂等性。
分布式事务选择
如何选择分布式事务方案
可以将业务按CAP定理来分析,业务是需要满足CP,还是AP。
若业务必须满足CP(强一致性),且接受一定的性能损耗,则使用3PC。
若业务为AP(最终一致性),只要业务能保证最终一致性即可,此时又需要分析业务是使用同步模型还是异步模型。若是同步模型则选择Saga,若异步则建议使用本地消息表。因TCC和事务消息都需要业务方来改造支持。