什么是事务?
是数据库执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。
事务的ACID四大特性:
原子性(Atomicity):事务作为一个整体被执行。
一致性(Consistency):从一个一致的状态转换到另一个一致的状态。
隔离性(Isolation):多个事务并发执行时,并发事务之间互相影响的程度。
持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中。
什么是分布式事务
事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点智商,且属于不同的应用,分布式事务需要保证这些操作要么全部成功,要么全部失败。
分布式事务解决方案
- XA两阶段提交2PC (强一致性)
涉及两个角色
一个事务协调者:负责协调多个参与者进行事务投票及提交(回滚)
多个事务参与者:本地事务执行者
处理的两个阶段
1、投票阶段:协调者将通知事务参与者准备提交或取消事务,然后进入表决过程。参与者将告知协调者自己的决策:同意(未提交)或取消(执行故障)
2、提交阶段:收到参与者的通知后,协调者再向参与者发出通知,根据反馈情况决定各参与者是否要提交还是回滚
优点:尽量保证数据的强一致,适合对数据强一致要求很高的关键领域
缺点:
- 同步阻塞:执行过程中,各节点是事务阻塞型。所有的事务,等待最长事务的执行。
- 单点故障:协调者发生故障,参与者会一直阻塞
无法解决的问题:协调者发出commit消息之后宕机,唯一接收到这条消息的参与者同时也宕机。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被提交了。
- 三段提交3PC(强一致)
两段提交的升级版
1、CanCommit阶段:询问阶段
2、PreCommit阶段:事务执行但不提交阶段
3、doCommit阶段:事务提交阶段
优点: 相对2PC,3PC主要解决单点故障问题,并减少阻塞,因为一旦参与者无法及时收到来自协调者的信息之后,他会默认执行commit。而不会一直持有事务资源并处于阻塞状态。
缺点: 由于网络原因,还是会存在数据不一致问题。
- TCC补偿机制(强一致)
核心思想:针对每个操作,都注册一个与其对应的确认和补偿操作。
例如: 小红要向小白转账100元,执行流程:
- 首先在 Try 阶段,要先调用远程接口检查小红的账户余额是否大于等于100元,若足够则对余额进行冻结,检查小白的账户状态是否正常。
- 在 Confirm 阶段,执行远程调用的转账的操作,扣除小红账户100元,小白账户加100元。
- 如果第2步执行成功,那么转账成功,小红账户解冻,流程结束。
- 如果第二步执行失败,则调用服务A的Cancel方法,账户余额回滚100元及解冻小红账户,同时调用服务B的Cancel方法,账户扣除100元。
优点: 跟2PC比起来,实现以及流程相对简单了一些。
缺点:
- 在2 3 4步中都有可能失败,从而导致数据不一致。
- TCC属于应用层的一种补偿方式,需要程序员在实现的时候多写很多补偿的代码,复杂业务场景下代码逻辑非常复杂。
- 幂等性无法确保。
- 本地消息表(MQ+Table)(最终一致)
工作流程:
- 消息生产方,需要额外建一个消息表,并记录消息发送状态。消息表和业务数据要在一个事务里提交,也就是说他们要在一个数据库里面。然后消息会经过MQ发送到消息的消费方。如果消息发送失败,会进行重试发送。
- 消息消费方,需要处理这个消息,并完成自己的业务逻辑。此时如果本地事务处理成功,表明已经处理成功了,如果处理失败,那么就会重试执行。如果是业务上面的失败,可以给生产方发送一个业务补偿消息,通知生产方进行回滚等操作。
- 生产方和消费方定时扫描本地消息表,把还没处理完成的消息或者失败的消息再发送一遍。
优点: 一种非常经典的实现,避免了分布式事务,实现了最终一致性。
缺点: 消息表会耦合到业务系统中,如果没有封装好的解决方案,会有很多杂活需要处理。
- 事务消息(RocketMQ)(最终一致)
有一些第三方的MQ是支持事务消息的,比如RocketMQ,他们支持事务消息的方式也是类似于采用的二阶段提交,但是市面上一些主流的MQ都是不支持事务消息的,比如 RabbitMQ 和 Kafka 都不支持(RabbitMQ、Kafka基于ACK机制)。
以阿里的 RocketMQ 中间件为例,流程为:
- 发送一个事务消息,这个时候,RocketMQ将消息状态标记为Prepared,注意此时这条消息消费者是无法消费到的。
- 执行业务代码逻辑。
- 确认发送消息,RocketMQ将消息状态标记为可消费,这个时候消费者才能真正消费到这条消息。
- 如果步骤3确认消息发送失败,RocketMQ会定期扫描消息集群中的事务消息,如果发现了Prepared消息,它会向消息发送端(生产者)确认。RocketMQ会根据发送端设置的策略来决定是回滚还是继续发送确认消息。这样就保证了消息发送与本地事务同时成功或同时失败。
优点: 实现了最终一致性,不需要依赖本地数据库事务。
缺点: 目前主流MQ中只有RocketMQ支持事务消息。
- Seata
核心组件:
- Transaction Coordinator (TC): 事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚。
- Transaction Manager ™: 控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议。
- Resource Manager (RM): 控制分支事务,负责分支注册、状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚。
工作流程:
- TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的事务ID(XID),XID 在微服务调用链路的上下文中传播。
- RM 向 TC 注册分支事务,接着执行这个分支事务并提交事务(重点:RM在此阶段就已经执行了本地事务的提交/回滚),最后将执行结果汇报给TC。
- TM 根据 TC 中所有的分支事务的执行情况,发起全局提交或回滚决议。
- TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求。