事务一致性
最后更新于
这有帮助吗?
最后更新于
这有帮助吗?
数据库事务:多个操作可以被视作一个完整的逻辑处理单元,要么全部执行,要么全部不执行,是不可分割的工作单元。
事务具有ACID的特性:
原子性:日志保证,undolog
一致性:锁保证
隔离性:锁保证
持久性:日志保证,redolog
事务是为了保证一致性产生的,AID是方式,C是目的。
涉及到多个数据库、多个服务时,多个库、多个服务之间就会存在数据一致性的问题,这种事务就是分布式事务。
分布式事务问题实际上就是分布式系统下的数据一致性问题。根据CAP和BASE理论解决一致性问题一般有强一致性与最终一致性方案。
强一致性方案比较适合对一致性的实时性要求高、性能要求较低的场景下;而最终一致性方案,则适合系统对性能的要求较高,实时性要求比较叫低的场景。
强一致性的场景下,通常会引入一个事务协调者,监控所有分支事务的运行状态。通常,所有分支事务会想进行”彩排“,彩排的目的是提高事务的成功概率,如果彩排成功,就会对所有分支事务提交,否则会通知所有的分支事务回滚。
而最终一致性方案因为对实时性要求比较低,解决方案就相对比较多。
XA规范
强一致性
2PC协议
强一致性
3PC协议
强一致性
TCC
最终一致性
先进行资源预留,成功提交,失败取消资源预留
Saga
最终一致性
提交时从前往后提交,回滚时从后往前做补偿操作
事件驱动
最终一致性
前一个事务提交成功后会发送事件给下一个事务,依次驱动到最后一个事务
事件表+定时任务+消息队列
最终一致性
事件驱动的优化,存储分支事务事件到事件表,并通过定时任务发送事件到其他服务处理分支事务
本地消息表
最终一致性
在主事务中记录分支事务的消息状态,然后向分支事务发送消息,根据所有消息的状态可对事务进行完成或回滚的操作
最大努力通知方案
最终一致性
事务处理失败重复尝试知道成功为止、事务处理失败通过其他查询接口对其数据(支付对账)
根据分布式事务的解决思路,就衍生出了XA规范。XA规范定义了事务协调者与数据库之间的规范,事务协调者用于通知数据库的开始、结束以及提交、回滚等。
上图中,TM就是协调者,RM是数据库,AP是应用程序。XA接口函数由数据库厂商提供。
分布式集群情况下,一般增加代理层来充当TM的角色,实现对事物的支持,由XA规范,引申出了:
2PC,两阶段提交
3PC,三阶段提交(几乎没有人用)
两阶段提交分为两个阶段:
第一阶段为投票阶段,事务协调者开启事务,让参与事务的各方进行执行演练,并收集执行结果
第二阶段为提交/回滚阶段,如果有所有方都投票成功,就会通知所有方进行提交。如果有任何一方投票失败,或者连接不通,就会通知所有方进行回滚。
两阶段提交可以尽可能的保证数据的一致性。
单点故障
协调者发生故障
解决方案:协调者改为集群部署
阻塞资源
占用数据库连接,性能低
解决方案:在一阶段的时候,直接提交事务,并记录提交前的数据状态。等到二阶段,如果成功,那就不用通知了。如果失败,将数据回滚到记录的上个状态中(Alibaba seata AT模式 就是这么做的,他通过undolog来完成的)。
数据不一致仍有可能发生
当演练成功后,通知所有的服务,这个阶段有可能通讯失败,就造成了数据不一致的情况。
解决方案:使用脚本检查异常情况,自动回滚
有了两阶段提交,为什么还需要三阶段提交协议?
事务参与者如果本身就不符合执行条件,如果继续开启事务执行sql,会占用数据库连接,造成性能损失。故在三阶段提交中,增加can commit
阶段,用于校验参与者是否可以提交,如果不可以,直接不开启事务。
为参与者提供超时机制,也就是在do commit
阶段,做更好的容错处理,提高事务成功的概率。
三阶段提交分为三个阶段,分别是:
can commit
:校验所有参与者是否可进行提交操作
如果反馈结果为成功,进行pre commit
阶段
如果有反馈结果为失败,执行 abort commit
,事务直接会被取消。can commit
返回失败的情况包含:
参与者返回no
协调者等待超时(包含参与者没有收到指令的情况)
pre commit
:同二阶段第一个相同,执行sql
如果反馈结果为成功,进行do commit
阶段
如果有反馈结果为失败,执行 abort commit
,并会进行数据回滚
do commit
:提交事务
参与者视角,可能发生超时的情况:
can commit
指令阶段,参与者不存咋超时情况
参与者在收到can commit
指令后并回复,但是没有收到pre commit
指令或abort commit
指令,这时会执行回滚操作
参与者在收到pre commit
指令后并回复,但是没有收到do commit
指令或abort commit
指令,这时候会直接执行提交操作(这是一个概率问题,前两个阶段的校验已经通过,后续大概率是会成功的,所以直接提交事务较为合适)。
TCC可以解决两个数据方的数据同步问题,比如Mysql和Redis的数据同步问题:
Try阶段,张三转账100元,将余额字段减去100,但是冻结字段增加100。而李四的冻结字段会加上100。
如果Try阶段成功,会执行Confirm
,这时张三的冻结字段减100,李四的冻结字段减100,但是余额增加一百。
如果Try阶段失败,会执行Cancel
,这时张三的冻结字段减100,余额增加100,恢复到了之前的状态,而李四的冻结字段减去了100,也恢复到了之前的状态。
所谓TCC就是给整个流程执行的过程中,增加一个中间的冻结态,如果操作失败,都可以根据中间台进行逆操作,从而恢复之前的状态。
优点和缺点:
系统的可用性高,异步处理,接口的响应速度快
相应的,所有事件的处理是通过消息传递的,有可能发生数据一致性的问题,只能尽可能保证最终一致性
支付回调,有可能发生回调失败的情况,可以增加重试次数。 并且,支付接口通常会提供查询接口,查询出已提交的支付信息的支付状态:
重复通知机制
消息校对机制