1. 2PC提交协议
- 准备阶段
- 协调者通知参与者做提交准备,然后进入决策投票过程
- 参与者收到通知后进行提交准备(执行本地事务,并将redolog,undolog写入日志),成功则告知协调者自己的投票为”同意”,否则告知投票为”取消”
提交阶段
【同步阻塞问题】 是同步阻塞协议,占用资源
- 【单点故障】 协调者挂了参与者会一致阻塞下去
【数据不一致】网络原因导致部分参与者未接收到提交请求,则会导致数据不一致
2. 3PC提交协议
2PC和3PC的区别是什么?
3pc比2pc多了一个can commit阶段,减少了不必要的资源浪费。因为2pc在第一阶段会占用资源,而3pc在这个阶段不占用资源,只是校验一下sql,如果不能执行,就直接返回,减少了资源占用。
- 引入超时机制。同时在协调者和参与者中都引入超时机制。
- T(Try):业务检查阶段,这阶段主要进行业务校验和检查或者资源预留;也可能是直接进行业务操作。
- C (Confirm):业务确认阶段,这阶段对Try阶段校验过的业务或者预留的资源进行确认。
- C (Cancel):业务回滚阶段,这阶段和上面的C (Confirm)是互斥的,用于释放Try阶段预留的资源或者业务。
撤销和确认操作的执行可能需要重试,因此还需要保证操作的幂等
相对于 2PC、3PC ,TCC 适用的范围更大,但是开发量也更大,毕竟都在业务上实现,而且有时候你会发现这三个方法还真不好写。
4. 消息队列+本地事件表方案
5. 可靠消息服务方案
6. 最大努力通知方案
7. SEATA
Seata的分布式事务解决方案是业务层面的解决方案,只依赖于单台数据库的事务能力。Seata框架中一个分布式事务包含3中角色:
- Transaction Coordinator (TC): 事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚。
- Transaction Manager (TM): 控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议。
- Resource Manager (RM): 控制分支事务,负责分支注册、状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚。
其中,TM是一个分布式事务的发起者和终结者,TC负责维护分布式事务的运行状态,而RM则负责本地事务的运行。如下图所示
下面是一个分布式事务在Seata中的执行流程:
- TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的 XID。
- XID 在微服务调用链路的上下文中传播。
- RM 向 TC 注册分支事务,接着执行这个分支事务并提交(重点:RM在第一阶段就已经执行了本地事务的提交/回滚)
- TM 根据 TC 中所有的分支事务的执行情况,发起全局提交或回滚决议。
- TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求。
为什么Seata在第一阶段就直接提交了分支事务?
Seata能够在第一阶段直接提交事务,是因为Seata框架为每一个RM维护了一张UNDO_LOG表(这张表需要客户端自行创建),其中保存了每一次本地事务的回滚数据。因此,二阶段的回滚并不依赖于本地数据库事务的回滚,而是RM直接读取这张UNDO_LOG表,并将数据库中的数据更新为UNDO_LOG中存储的历史数据。
如果第二阶段是提交命令,那么RM事实上并不会对数据进行提交(因为一阶段已经提交了),而实发起一个异步请求删除UNDO_LOG中关于本事务的记录。
seata第一阶段提交会造成脏读吗?
存在于seata之外的数据修改seata无法进行控制,对于这种数据校验失败的回滚也不能进行覆盖性的回滚,这个决策只能交给用户。所以对于seata AT模式的一个原则是数据修改的入口都要交给seata事务控制。即:数据修改的服务都应该纳入到seata的事务控制内
seata第一阶段提交获取全局锁?
RM在同一个本地事务中执行业务SQL和UNDO_LOG数据的插入。在提交这个本地事务前,RM会向TC申请关于这条记录的全局锁。如果申请不到,则说明有其他事务也在对这条记录进行操作,因此它会在一段时间内重试,重试失败则回滚本地事务,并向TC汇报本地事务执行失败
seata全局锁何时释放?
RM在事务提交前,申请到了相关记录的全局锁,因此直接提交本地事务,并向TC汇报本地事务执行成功。此时全局锁并没有释放,全局锁的释放取决于二阶段是提交命令还是回滚命令,详细请看seata原理