1 事务
众所周知,事务具有ACID四大特性:
原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态是指数据库中的数据应满足完整性约束。除此之外,一致性还有另外一层语义,就是事务的中间状态不能被观察到(这层语义也有说应该属于原子性)。
隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行,如同只有这一个操作在被数据库所执行一样。
持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中。在事务结束时,此操作将不可逆转。
事务提供要么操作全部成功,要么全部失败。
以mysql的InnoDB存储引擎为例,事务的隔离性是通过数据库锁的机制实现的,持久性通过redo log(重做日志)来实现,原子性和一致性通过Undo log来实现。
2 分布式事务
以上所述的单机事务是通过将操作限制在一个会话内通过数据库本身的锁以及日志来实现ACID,那么分布式环境下该如何保证ACID特性呢?分布式事务有多种事务解决方案,使多个微服务下的数据库操作,形成一个整体,每个微服务下的本地事务,与其他微服务之间通过相互通信的方式,彼此形成一个整体,全部成功,或全部失败。此时的分布式事务同样适用于ACID原则,事务隔离级别应同样适用于分布式事务,比如读已提交。
实现方式主要有以下几种:
- XA协议实现分布式事务
- TCC协议实现分布式事务
2.1 XA协议
XA是一个分布式事务协议,由Tuxedo提出。XA中大致分为两部分:事务管理器和本地资源管理器。其中本地资源管理器往往由数据库实现,比如Oracle、DB2这些商业数据库都实现了XA接口,而事务管理器作为全局的调度者,负责各个本地资源的提交和回滚。XA实现分布式事务的原理如下:
(图片引自参考)
基于 XA 协议的两阶段提交(2PC)步骤如下:
准备阶段:事务协调者向所有参与者发送Prepare请求,参与者执行事务操作,但不提交。参与者检查自身事务执行情况,如果可以提交,则记录日志并响应Yes给协调者;否则响应No。
提交阶段:协调者根据参与者的响应来决定下一步操作。如果所有参与者都返回Yes,协调者发送Commit请求,参与者正式提交事务;如果有任何一个参与者返回No或者在规定时间内没有收到响应,协调者发送Rollback请求,参与者回滚事务。
应用程序通过与事务管理器开启全局事务,待全局事务开启之后,访问本地资源管理器,本地资源管理器向事务管理器申请注册分支事务,在完成逻辑操作之后,通过事务管理器,进行两阶段提交协议 ,进行协调各个本地资源管理器进行提交或者回滚操作。
XA的优点:
对业务无侵入,对资源管理器要求高
XA的缺点:
单点故障:一旦事务管理器出现故障,整个系统不可用(参与者都会阻塞住)
数据不一致:在阶段二,如果事务管理器支发送了部分commit消息,此时网络发生异常,那么部分参与者接收到commit消息,也就是说只有部分参与者提交了事务,使得系统数据不一致。
响应时间较长:参与者和协调者资源被锁住(数据库SQL复杂,行锁,响应时间很长),提交或者回滚之后才能释放,且易发生死锁
不确定性:当事务管理器发送commit之后,并且此时只有一个参与者收到了commit,那么当该参与者与事务管理器同时死机之后,重新选举的事务管理器无法确定该条消息是否发送提交成功。
另外优化后的三阶段提交(3PC)步骤如下:
CanCommit 阶段:协调者向参与者发送CanCommit请求,询问是否可以执行事务提交操作。参与者检查自身状态,如果可以进行事务提交,则返回Yes,否则返回No。
PreCommit 阶段:如果协调者收到所有参与者的Yes响应,会进入PreCommit阶段,向参与者发送PreCommit请求,参与者执行事务操作,但不提交。此时参与者会记录事务日志,为可能的提交或回滚做准备。
DoCommit 阶段:如果协调者在PreCommit阶段收到所有参与者的成功响应,或者等待超时后没有收到任何参与者的失败响应,就会发送DoCommit请求,让参与者提交事务。如果在PreCommit阶段有参与者返回失败响应,或者等待超时,协调者会发送Abort请求,让参与者回滚事务。
可以看出,第一阶段:can commit阶段,协调者询问事务参与者,是否有能力完成此次事务,如果都返回yes,则进入第二阶段,否则中断事务,向所有参与者发送abort请求,另外两阶段就是2PC,也就是上述的两阶段协议。
2.2 TCC协议
TCC(Try-Confirm-Cancel)分布式事务模型相对于 XA 等传统模型,其特征在于它不依赖资源管理器(RM)对分布式事务的支持,而是通过对业务逻辑的分解来实现分布式事务。
(图片引自参考)
TCC分为两个阶段,分别如下:
第一阶段:Try(尝试),主要是对业务系统做检测及资源预留 (加锁,锁住资源)
第二阶段:本阶段根据第一阶段的结果,决定是执行confirm还是cancel
- Confirm(确认):执行真正的业务(执行业务,释放锁)
- Cancle(取消):是预留资源的取消(出问题,释放锁)
优点:
并发性能好
缺点:
侵入业务层, 业务层需要作相应的改造。
2.3 Saga 模式
SAGA的意思是“长篇故事、长篇记叙、一长串事件”,它起源于1987年普林斯顿大学在ACM发表的一篇论文。
事务分解:将一个大的分布式事务分解为一系列的本地事务,每个本地事务都有对应的正向操作和补偿操作。
顺序执行:按照一定的顺序依次执行这些本地事务的正向操作。例如,在一个电商订单处理的分布式事务中,可能依次执行创建订单、扣减库存、更新物流信息等本地事务。
补偿机制:如果在执行过程中某个本地事务失败了,就会按照相反的顺序执行已经执行成功的本地事务的补偿操作,来达到回滚的目的。比如,如果扣减库存失败,那么就需要回滚创建订单的操作。
(图片引自参考)
2.4 消息队列(可靠消息最终一致性)
消息发送:在事务操作前,先将消息发送到消息队列。消息中包含了需要在其他服务或节点上执行的操作信息。比如在一个订单创建和库存扣减的分布式事务中,订单服务在创建订单前,先将包含订单商品信息的消息发送到消息队列。
本地事务执行:发送消息成功后,执行本地事务,比如创建订单记录等操作。
消息消费:其他服务从消息队列中获取消息,并根据消息内容执行相应的操作,比如库存服务获取到消息后,执行扣减库存的操作。通过消息的可靠投递和消费确认机制,保证最终数据的一致性。如果消息消费失败,可以进行重试或者通过补偿机制来处理。
(图片引自参考)
参考:
https://blog.csdn.net/qq_36142146/article/details/85247960
https://www.cnblogs.com/zengkefu/p/5742617.html
https://blog.csdn.net/hhgh_/article/details/146163928
https://blog.csdn.net/weixin_46619605/article/details/145563957
https://blog.csdn.net/huanghuozhiye/article/details/136792391
https://blog.csdn.net/softshow1026/article/details/135690475