1.什么是分布式事务
当系统采用分布式部署,数据就会分散在各个子系统的数据库。在一个子系统中保证数据要么全部提交,要么全部失败的操作叫本地事务。在分布式系统中,分布式事务就是指各个子系统的数据要么全部提交成功,要么全部提交失败。比如用户下单,需要订单系统生成订单、付款系统向用扣款成功、库存系统扣减商品库存等操作,如果已生成订单并付款成功,库存系统扣减商品数量失败,就会产生脏数据。
分布式事务通过引入协调者的角色,对各个子系统状态进行统一。
2.两阶段提交(2pc)
2.1 两个阶段指
准备阶段(除了没有提交,都做了)
提交阶段(要么提交,要么回滚)
2.2 两阶段实现
准备阶段
1)协调者通知所有参与者,然后等待参与者回执
2)参与者收到通知开始执行事务操作,并将Undo和Redo信息写入日志(只是执行了事务操作,并没有提交commit或者回滚rollback)
3)参与者给协调者返回响应,参与者事务操作执行成功,返回“同意”,参与者事务执行失败,返回“中止”。
提交阶段
当协调者收到所有参与者响应消息都是“同意”时
1)协调者向参与者发送“提交(commit)”请求
2)参与者正式完成“提交(commit)”操作,并释放整个事务期间占用的资源
3)参与者向协调者发送“完成”消息
4)协调者收到所有参与者返回“完成”消息后,完成事务
当协调者收到有参与者响应消息是“中止”时
1)协调者向所有参与者发送“回滚(rollback)”请求 2)参与者利用之前写入的Undo信息执行回滚,并释放整个事务期间占用的资源
3)参与者向协调者发送“回滚完成”消息 4)协调者收到所有参与者返回的“回滚完成”消息后,取消事务
2.3 两阶段提交(2pc)优缺点
1)同步阻塞
执行过程中,所有参与者节点都是事务阻塞型的,当参与者占用公共资源时,其他第三方服务或者节点访问公共资源不得不处于阻塞状态,效率低下。
2)单点故障
分布式事务中协调者是非常重要的一环,如果协调者故障,会导致参与者事务一直阻塞下去。如果协调者故障发生在第二阶段,参与者都还处在锁定事务状态,无法继续完成事务。
即使协调者是也是分布式机制,也可能因为主节点在没有把参与者状态同步给从节点前挂掉,导致从节点当选主节点后,无法得知参与者状态,从而使参与者一直处在锁定事务状态。
4)数据不一致
在第二阶段提交过程中,协调者向参与者发送提交请求之后,发生网络故障,导致部分参与者收到提交请求,执行commit操作,一部分没有收到提交请求,事务无法提交,从而导致整个分布式系统数据不一致,出现脏数据。
网络故障可以尝试重试或者记录日志,必须保证第二阶段执行成功,不然数据会不一致。
5)不确定性
协调者再发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交。
新协调者对所有参与者发送提交命令,由参与者自己实现幂等逻辑。
3.三阶段提交(3pc)
3pc对比2pc,引入了协调者和参与者超时机制,并新增了询问阶段,询问阶段起到统一参与者状态的作用,当参与者进入预提交阶段,则可以确定其他参与者也进入了预提交阶段。
3.1 三个阶段指
询问阶段(canCommit):询问参与者是否可以执行事务操作
预提交阶段(preCommit):除了没有提交事务,其他事务操作都执行了
提交阶段(doCommit):提交事务,或者回滚事务
3.2 三阶段实现
询问阶段(canCommit)
1)协调者向所有参与者发送canComit请求,询问是否可以执行事务操作(不是真正执行事务,只是询问)
2)参与者收到canCommit请求,判断自身状态,如果可以执行请求就返回“Yes”,并进入预备状态,斗则返回“No”
预提交阶段(preCommit)
当协调者收到有参与者响应消息是“Yes”时
1)协调者向参与者发送preCommit请求
2)参与者执行事务操作,并把Undo和Redo信息记录到日志中
3)参与者执行成功执行事务操作,向协调者返回“ACK”响应,参与者等待最终指令
当协调者收到有参与者响应消息是“No”时
1)协调者向所有参与者发送abort请求
2)参与者收到来自协调者的abort请求之后(或超时之后,仍未收到协调者的请求),执行事务的中断
提交阶段(doCommit)
当协调者收到有参与者响应消息是“ACK”时,执行请求
1)协调接收到参与者发送的ACK响应,从预提交状态进入到提交状态。并向所有参与者发送doCommit请求
2)参与者接收到doCommit请求之后,执行正式的事务提交。并在完成事务提交之后释放所有事务资源
3)参与者事务提交完之后,向协调者发送ACK响应
4)协调者接收到所有参与者的ACK响应之后,完成事务
当协调者收到有参与者响应消息不是“ACK”,或者参与者响应超时的时候,事务回滚
1)协调者向所有参与者发送abort请求
2)参与者接收到abort请求之后,利用undo信息来执行事务的回滚操作,并在完成回滚之后释放所有的事务资源
3)参与者完成事务回滚之后,向协调者发送ACK消息
4)协调者接收到参与者反馈的ACK消息之后,执行事务的中断
协调者超时,参与者无法及时收到doCommit消息,回自动进入提交阶段,执行commit操作。
注:当进入第三阶段时,说明参与者在第二阶段已经收到了PreCommit请求,那么协调者产生PreCommit请求的前提条件是他在第二阶段开始之前,收到所有参与者的CanCommit响应都是Yes。一旦参与者收到了PreCommit,意味他知道大家其实都同意修改了)所以,一句话概括就是,当进入第三阶段时,由于网络超时等原因,虽然参与者没有收到commit或者abort响应,但是他有理由相信:成功提交的几率很大。
3.3 三阶段提交(3pc)优缺点
1)优点:解决阻塞问题
因为引入了超时机制和询问机制,在提交阶段,参与者无法及时收到协调者doCommit请求,参与者会自动执行doCommit操作,不会一直持有事务资源并处于阻塞状态。
2)缺点:数据不一致
当协调者无法及时给参与者发送消息,参与者自动进入提交阶段时,如果应该执行回滚操作,就会带来数据不一致的影响。
4.TCC(try-confirm-cancle)
4.1 TTC的操作
初步操作Try:预留和锁定资源
确认操作Confirm:正在执行操作
取消操作Cancel:撤销预留和锁定的资源
4.2 TCC实现
初步操作Try
UPDATE company SET frozen = frozen + #{money} WHERE id = #{id}
确认操作Confirm
UPDATE company SET money = money + #{money},frozen =frozen - #{money} WHERE id = #{id}
取消操作Cancel
UPDATE company SET frozen = frozen - #{money} WHERE id = #{id}
4.3 TCC优缺点
1)实现tcc的业务成本,一个逻辑得写3套,分别对应try,confirm,cancel
2)confirm和cancel操作的执行成本
3)记录日志的成本和开销
4)复杂业务,tcc的cc难以处理,难以实现
5)如果框架不考虑幂等,事务内cc实现需要考虑幂等
4.4 TCC适用场景
1)强隔离性,严格一致性要求的业务
2)执行时间较短的业务
5.本地消息表
本地消息表即在本地存储一个本地消息数据,一般是存放在数据库里,业务数据和消息数据在同一个事物里入库,保证同时成功或者失败回滚。
本地事务执行成功后,定时轮询本地消息表,未成功的消息反复重试。
本地消息表保证的是事务的最终一致性,容忍了数据暂时不一致的情况。比如用户下单以后,给用户发送消息、刷新购物车,可以容忍暂时滞后执行。
6.阿里巴巴的分布式中间件fescar
6.1 概念与实现
Transaction Coordinator (TC): 事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚。
Transaction Manager ™: 控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议。
Resource Manager (RM):控制分支事务,负责分支注册、状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚。 一个典型的分布式事务过程:
1.TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的 XID。
2.XID 在微服务调用链路的上下文中传播。
3.RM 向 TC 注册分支事务,将其纳入 XID 对应全局事务的管辖。
4.TM 向 TC 发起针对 XID 的全局提交或回滚决议。
5.TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求。
6.2 数据库实现回滚方式
Phase1: Fescar 的 JDBC 数据源代理通过对业务 SQL 的解析,把业务数据在更新前后的数据镜像组织成回滚日志,利用本地事务 的 ACID 特性,将业务数据的更新和回滚日志的写入在同一个 本地事务 中提交。
这样,可以保证:任何提交的业务数据的更新一定有相应的回滚日志存在。
基于这样的机制,分支的本地事务便可以在全局事务的 Phase1提交,马上释放本地事务锁定的资源。
Phase2:如果决议是全局提交,此时分支事务此时已经完成提交,不需要同步协调处理(只需要异步清理回滚日志),Phase2 可以非常快速地完成。
如果决议是全局回滚,RM 收到协调器发来的回滚请求,通过 XID 和 Branch ID 找到相应的回滚日志记录,通过回滚记录生成反向的更新
SQL 并执行,以完成分支的回滚。
6.3 隔离级别
最高支持到读已提交
总结
2pc和3pc是基于数据库事务的分布式事务方案,提交和回滚建立在事务上,没有业务的入侵,但是资源锁定会影响业务执行效率。
tcc是基于业务的分布式事务方案,有业务入侵,而且同一个方法需要实现三次(资源锁定、资源提交、资源回滚)。
2pc、3pc、tcc要求保障数据强一致性,成功全部提交,失败全部回滚。 本地消息表保证的是数据最终一致性,可以容忍一定的延迟。
参考文档
面试必问:分布式事务六种解决方案 /p/183753774分布式事务-01:分布式事务产生原因及相关概念 /developer/article/1446247分布式事务-02:2PC 二阶段提交协议实现过程及原理 /developer/article/1995289分布式事务-03:3PC 三阶段提交协议实现过程及原理 /developer/article/1995320分布式事务-04:TCC实现过程及原理 /developer/article/1995322分布式事务系列–SpringCloud整合byteTCC框架0.4.x版本 /developer/article/1402493分布式事务系列–SpringCloud整合byteTCC框架0.5.x版本1 /developer/article/1995224分布式事务系列–SpringCloud整合byteTCC框架0.5.x版本2 /developer/article/1399657分布式事务系列–是选TCC还是SAGA /developer/article/1405126分布式事务解决方案FESCAR /developer/article/1386495