分布式事务
文章目录
一、分布式场景下的数据一致性问题形成原因剖析
1. 分布式事务背景背景知识
什么情况下会出现分布式事务?——关系库的扩展
- 水平分库
- 场景:业务量变得非常庞大
- 当业务量变大的时候,分表、分库是必然出现的事情(单表、单库有性能优化瓶颈),当分库场景出现的时候,分布式事务的使用场景就出现了。
- 垂直分库
- 场景:业务按模块划分,数据库也因此互相隔离
- 适应微服务架构,每个模块都应该有自己的库(为了实现模块的独立与隔离),那么微服务间的事务大概率是在两个库之间的事务,也就是所谓的分布式事务。
总结
- 跨数据库分布式事务
- 跨服务分布式事务
- 混合式分布式事务
- 就是同时跨数据库分布式事务+跨服务式分布式事务
2. 对于刚性事务
刚性事务的“刚性”是对系列操作的原子性的“刚性需求”——这一系列操作,要么全部完成,要么全部取消
2pc
基本流程:a准备,b准备;一切正常;a提交,b提交。
缺陷:可能会出现a提交了,b提交出现问题的情况。为了解决这个问题我们引入3pc。
* 这个缺陷出现的可能性非常非常低。
3pc
在2pc的基础上在提交阶段之前增加了一个对齐阶段,确认各个分支事务的可提交状态。但是只能尽量减少原子提交操作失败的可能性,不能根除。
XA
定义:**一种两阶段提交协议。**XA规定第一阶段对操作进行记录,不允许提交,只允许给交易中间件发送可提交信号,第二阶段由交易中间件审查可提交状态后正式提交,此过程中任意一个预提交操作失败都将导致此全局事务的回滚。
帮助理解:上面的2pc、3pc就是XA协议的两种实现形式。
缺陷:性能衰减很厉害(约10倍)。因为为了保证原子性与正确性,我们可能会需要锁住相关的行或者表。
适用的场景:低并发并且数据敏感的情况。(性能低,但是数据一致性能够很好的保证)
知识补充一
XA是X/Open DTP组织(X/Open DTP group)定义的两阶段提交协议,XA被许多数据库(如Oracle、DB2、SQL Server、MySQL)和中间件等工具(如CICS 和 Tuxedo).本地支持。
X/Open DTP模型(1994)包括应用程序(AP)、事务管理器(TM)、资源管理器(RM)、通信资源管理器(CRM)四部分。
一般情况下,某一数据库无法知道其它数据库在做什么,因此,在一个DTP环境中,交易中间件是必需的,由它通知和协调相关数据库的提交或回滚。而一个数据库只将其自己所做的操作(可恢复)影射到全局事务中。
在第一阶段:交易中间件请求所有相关数据库准备提交(预提交)各自的事务分支,以确认是否所有相关数据库都可以提交各自的事务分支。当某一数据库收到预提交后,如果可以提交属于自己的事务分支,则将自己在该事务分支中所做的操作固定记录下来,并给交易中间件一个同意提交的应答,此时数据库将不能再在该事务分支中加入任何操作,但此时数据库并没有真正提交该事务,数据库对共享资源的操作还未释放(处于锁定状态)。如果由于某种原因数据库无法提交属于自己的事务分支,它将回滚自己的所有操作,释放对共享资源上的锁,并返回给交易中间件失败应答。
在第二阶段:交易中间件审查所有数据库返回的预提交结果,如所有数据库都可以提交,交易中间件将要求所有数据库做正式提交,这样该全局事务被提交。而如果有任一数据库预提交返回失败,交易中间件将要求所有其它数据库回滚其操作,这样该全局事务被回滚。
3. 对于柔性事务
一致性层面来说,柔性事务是指事务中的操作对于即时数据一致性并没有那么敏感的一系列操作。
柔性事务不追求即时数据一致,但在之后需要能够保证最终结果的一致。
隔离性层面来说,柔性事务要求并行事务间不可影响,事务中间结果可见性允许安全放宽。
TCC (try/confirm/cancel)
指使用try-confirm或者try-cancel这样一种模式来保证最终结果是一致的。
TCC模型分为三个阶段:(用下订单来举例子,下订单涉及订单服务、库存服务)
-
Try - 事务预处理 检测资源、预留资源,以库存为例,下了三袋螺蛳粉,在此阶段就冻结三袋螺蛳粉,而订单记录是新增的记录,不需要冻结某种资源,则订单的try阶段执行空方法。
逻辑核心:声明并获取所需要的资源,在confirm的时候就不需要担心资源不足而回滚的问题。
-
Confirm - 确认冻结资源被使用,各分支事务各自提交即可(因为不用担心资源不足导致的回滚)。
-
在try阶段冻结资源失败,也就是资源不足无法完成事务时,调用此方法释放被冻结的资源。
优势
-
性能好
说是分布式事务,其实几乎可以约等于一个个本地的事务。做好了准备工作,满足条件之后只要一个一个执行完毕就行。有点项目管理中“管理重心前移”的味道了。
管理重心前移:把做事的重点放在计划于准备上,之后只要按计划执行每一步就行了。
-
模型简单
易于理解,请求资源-确认资源,请求资源失败-释放已获得的资源,你有没有感觉像是携程买火车票?
缺陷
- 实际项目中可能会有请求重试机制,那么每个阶段对幂等性都会有要求,对使用者的代码能力要求高。
- 对高并发的事务支持并不友好,任意一个服务本地提交之后,如果有其他的事务对提交后的数据进行了修改,会大幅度提升校验与回滚操作的难度。
- 模型简单,但实现难度很大,如果考虑其他的诸如并发与事务隔离以及不可控的网络引起的诸多问题,此模式的实现可能并不像预想的那么简单。
辨析:TCC模型是不是与XA模型非常相似?
同:都符合二阶段模型:各分支事务预操作 - 各分支事务提交
异:1. 最本质的区别就是能否提前提交本地事务:
- TCC模型中,本地事务一旦完成,那么直接提交即可,数据一致性通过二次检查来保证。
- XA模型中,全局事务会长期持有各本地事务的锁,直到所有分支事务完成后统一提交。
基于以上差异,TCC的性能远优于XA也是一目了然的事。
2. XA是对业务不侵入的,一个功能完成一个接口,不需要过多的关心事务层面的事;TCC则不同,可能你需要花2倍甚至几倍于开发业务代码的时间完成确认与回滚接口。
saga
名称来源于1987年的论文,Sagas。
将一个任务多、耗时长的长事务进行**拆分成若干子事务,每个子事务要求两个接口,一个执行接口,一个回退补偿接口**,回退补偿接口是执行接口的逆操作。
当子事务失败需要回退时,就逆序顺次执行回退补偿接口,达成长事务的回滚。
(saga在之后会有详细的介绍,在此处不多赘述)
事务消息
保证本地写入发消息的原子性,但是没法保证消息被接收后成功运行。
其实是个分布式事务的伪实现。
最大努力通知事务
发起方不断,在收到成功信号前,不断重试。应当需要保证事务整体的幂等性。
刚性事务的解决方案可用吗?
能满足刚性事务的解决方案一定能解决柔性事务的需求。
刚性事务解决方案在性能方面一般来说都是是最低的,所以,能用柔性事务的一般手段解决的,尽量不使用刚性事务解决方案。
给方案选择提供一些参考
显而易见,XA性能低,柔性事务解决方案一般来说性能更为友好,但是相对的数据一致的即时性没有那么高。
mysql原生支持刚性事务,而我们在高并发对高性能有需求的场景下来讲,将业务处理成柔性事务肯定是t0级的选择,但是有一些业务可能对时间与数据一致性都很敏感,
思考:目前哪些业务场景是刚性事务?而哪些业务是可以做成柔性事务的呢?
参考文章: