什么是分布式事务 指事务的参与者、⽀持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。 简单的说,就是⼀次⼤的操作由不同的⼩操作组成,这些⼩的操作分布在不同的服务器上,且属于不同的应⽤分布式事务需要保证这些⼩操作要么全部成功,要么全部失败。 本质上来说,分布式事务就是为了保证不同数据库的数据⼀致性
产生的原因 业务发展,数据库的拆分-分库分表 SOA和微服务架构的使⽤ 多个微服务之间调⽤异常,⽹络异常、请求超时、数据库异常、程序宕机等

首先介绍一下 分布式事务下数据最终⼀致性-BASE理论 CAP 中的⼀致性和可⽤性进⾏⼀个权衡的结果,核⼼思想就是: 我们⽆法做到强⼀致,但每个应⽤都可以根据⾃身的业务特点,采⽤适当的⽅式来使系统达到最终⼀致性, 来⾃ ebay 的架构师提出 Basically Available(基本可⽤) 假设系统,出现了不可预知的故障,但还是能⽤, 可能会有性能或者功能上的影响,⽐如RT是10ms,变成50ms Soft state(软状态) 允许系统中的数据存在中间状态,并认为该状态不影响系统的整体可⽤性,即允许系统在多个不同节点的数据副本存在数据延时 Eventually consistent(最终⼀致性) 系统能够保证在没有其他新的更新操作的情况下,数据最终⼀定能够达到⼀致的状态,因此所有客户端对系统的数据访问最终都能够获取到最新的值
关于数据⼀致性 强⼀致:操作后的能⽴⻢⼀致且可以访问(性能最低) 弱⼀致:容忍部分或者全部访问不到相同 最终⼀致:弱⼀致性经过多⼀段时间后,都⼀致且正常
分布式事务的常见解决方案概览(这里先简单介绍,后面详细讲解) 常⻅分布式事务解决⽅案 方案1.2PC 和 3PC:两阶段提交, 基于XA协议 方案2.TCC:Try、Confirm、Cancel **方案3.**事务消息:最⼤努力通知型 分布式事务分类 刚性事务:遵循ACID 柔性事务:遵循BASE理论 相应方案详细讲解 方案1:2PC 和 3PC(刚性事务) 前置知识 X/OpenDTP 事务模型是X/Open 这个组织定义的⼀套分布式事务的标准,也就是 定义了规范和 API 接⼝,由各个⼚商进⾏具体的实现DTP 是分布式事物处理(Distributed TransactionProcessing)的简称
XA协议 XA是由X/Open组织提出的分布式事务规范。 XA规范主要定义了(全局)事务管理器™和(局 部)资源管理器(RM)之间的接⼝主流的数据库产品都实现了XA接⼝,是⼀个双向的系统接⼝,在事务管理器以及多个资源管理器之间作为通信桥梁 JTA:Java Transaction API,java根据XA规范提供的事务处理标准 AP:application, 应⽤程序也就是业务层,微服务等 RM:Resource Manager,资源管理器。⼀般是数据库,也可以是其他资源管理器,⽐如消息队列 ⽂件系统TM :Transaction Manager ,事务管理器、事务协调者,负责接收来⾃⽤户程序(AP)发起的 XA 事务指令,并调度和协调参与事务的所有 RM(数据库),确保事务正确完成 在分布式系统中,每⼀个机器节点能够明确知道⾃⼰在进⾏事务操作过程中的 结果是成功还是失败,但⽆法直接获取到其他分布式节点的操作结果当⼀个事务操作跨越多个分布式节点的时候,为了保持事务处理的 ACID 特性,需要引⼊⼀个“协调者”(TM)来统⼀调度所有分布式节点的执⾏逻辑,这些被调度的分布式节点被称为 AP。TM 负责调度 AP 的⾏为,并最终决定这些 AP 是否要把事务真正进⾏提交到(RM)
实现原理 XA协议规范-实现分布式事务的原理如下 ⼀般习惯称为 两阶段提交协议(The two-phase commit protocol,2PC)是XA⽤于在全局事务中协调多个资源的机制,MySql5.5以上开始⽀持 准备阶段: 事务管理器给每个参与者都发送Prepared消息,每个数据库参与者在本地执⾏事务,并写本地的Undo/Redo⽇志,此时事务没有提交。 Undo⽇志是记录修改前的数据,⽤于数据库回滚 Redo⽇志是记录修改后的数据,⽤于提交事务后写⼊数据 提交阶段: 如果事务管理器收到了参与者的执⾏失败或者超时消息时,直接给每个参与者发送回滚(Rollback)消息,否则发送提交(Commit)消息;参与者根据事务管理器的指令执⾏【提交】或者【回滚】操作,并释放事务处理过程中使⽤的锁资源 注意:必须在最后阶段释放锁资源。

方案1总结 好处 XA协议简单,数据库⽀持XA协议,开发使⽤成本⽐较低对业务侵⼊很⼩,最⼤的优势就是对使⽤⽅透明 ⽤户可以像使⽤本地事务⼀样使⽤基于 XA 协议的分布式事务,能够严格保障事务 ACID 特性 缺点 事务执⾏过程中需要将所需资源全部锁定,也就是俗称的刚性事务 性能不理想,占⽤锁资源⽐较多,⾼并发常⻅下⽆法满⾜商业付费数据库⽀持好,mysql⽬前⽀持不是很完善 基于 XA 协议的 除了2PC,还有 3PC等 三段提交(3PC)是⼆阶段提交(2PC)的⼀种改进版本 ,为解决两阶段提交协议的阻塞问题 采⽤超时机制,解决TM故障后RM的阻塞问题,但与此同时却多了⼀次⽹络通信,性能上也不理想 2PC和3PC⽬前使⽤不是很多,简单了解即可
方案2.TCC(柔性事务) 将事务提交分为 Try:完成所有业务检查( ⼀致性 ) ,预留必须业务资源( 准隔离性 ) Confirm :对业务系统做确认提交,默认Confirm阶段不会出错的 即只要Try成功,Confirm⼀定成功 Cancel : 业务执⾏错误,需要回滚的状态下执⾏的业务取消,预留资源释放, 进⾏补偿性 TCC 事务和 2PC 的类似,Try为第⼀阶段,Confirm/Cancel为第⼆阶段,它对事务的提交/回滚是通过执⾏⼀段 confirm/cancel 业务逻辑来实现,并且也并没有全局事务来把控整个事务逻辑 方案2总结 优点: 它把事务运⾏过程分成 Try、Confirm/Cancel 两个阶段每个阶段由业务代码控制,这样事务的锁⼒度可以完全⾃由控制 不存在资源阻塞的问题,每个⽅法都直接进⾏事务的提交 缺点 在业务层编写代码实现的两阶段提交,原本⼀个⽅法,现在却需要三个⽅法来⽀持 对业务的侵⼊性很强,不能很好的复⽤ 注意:使⽤TCC时要注意Try - Confirm - Cancel 3个操作的幂等控制,由于⽹络原因或者重试操作都有可能导致这⼏个操作的重复执⾏

方案3:事务消息 消息队列提供类似Open XA的分布式事务功能,通过消息队列事务消息能达到分布式事务的最终⼀致
半事务消息 暂不能投递的消息,发送⽅已经成功地将消息发送到了消息队列服务端,但是服务端未收到⽣产者对该消息的⼆次确认,此时该消息被标记成“暂不能投递”状态,处于该种状态下的消息即半事务消息。 消息回查 由于⽹络闪断、⽣产者应⽤重启等原因,导致某条事务消息的⼆次确认丢失,消息队列服务端通过扫描发现某条消息⻓期处于“半事务消息”时,需要主动向消息⽣产者询问该消息的最终状态(Commit或是Rollback),该询问过程即消息回查
⽬前较为主流的MQ,⽐如ActiveMQ、RabbitMQ、Kafka、RocketMQ等,只有RocketMQ⽀持事务消息 如果其他队列需要事务消息,可以开发个消息服务,⾃⾏实现半消息和回查功能 好处 事务消息不仅可以实现应⽤之间的解耦,⼜能保证数据的最终⼀致性 同时将传统的⼤事务可以被拆分为⼩事务,能提升效率不会因为某⼀个关联应⽤的不可⽤导致整体回滚,从⽽最⼤限度保证核⼼系统的可⽤性 缺点 不能实时保证数据⼀致性 极端情况下需要⼈⼯补偿,⽐如 假如⽣产者成功处理本地业务,消费者始终消费不成功

图片来源:rocketmq官⽅⽂档及XD课堂。