ACID和BASE这是事务实现的两种基础理论,
ACID是刚性事务,强调的是隔离性和强制一致性,隔离性的话就导致事务操作的资源在事务结束以前要一直被锁定占用,又因为强一致性,如果一个事务中包含了多个子事务,就导致了多个事务一次性完成,但是要是万一其中一个事务耗时很久,这样就会导致其他的事务一直占据着资源没法释放,从而影响整个系统的吞吐。
BASE是柔性事务,基本可用 可以保证分布式事务参与方不一定同时在线。柔性状态 允许系统状态更新有一定的延时,这个延时对客户来说不一定能察觉。最终一致性 通常是通过消息可达的方式保证系统的最终一致性。
XA是一种事务规范,主要是通过两阶段提交来完成分布式事务,两阶段提交基于ACID理论,这中间主要包括两个角色:资源管理器和事务管理器,
资源管理器主要负责我们的数据库等资源,
事务管理器就是一个中间件主要负责多个事物之间的协调,
场景如下:一次业务请求可能需要两个事务,
XA数据源也就是支持XA事务的数据源。
TCC是一种分布式事务解决方案:Try-Confirm-Cancel,TCC是基于BASE理论,
上面的解释可能不太容易明白:举个例子,你有女朋友,你在某宝要买100包杜蕾斯,这个流程是什么呢?
Try阶段:业务先去检查库存还有多少,加入还有1000 然后减去100(被记录下来) 这个时候库存剩下900
Confirm阶段:根据Try阶段的结果,如果满足100个,也就是操作生效,这个时候业务Try阶段减得的库存就直接生效了
CanCel阶段:如果Try阶段发现不满100个,这个时候就根据操作记录回滚,将库存再加上100(这个是在Try阶段被记录了的)就行了。
Saga其实是30年前的一篇数据库论文里提到的一个概念。在论文中一个Saga事务就是一个长期运行的事务,这个事务是由多个本地事务所组成, 每个本地事务有相应的执行模块和补偿模块,当saga事务中的任意一个本地事务出错了, 可以通过调用相关事务对应的补偿方法恢复,达到事务的最终一致性。
Saga对服务的要求:幂等性和补偿可交换原则
因为可能因为网络问题,会导致出现超时重试的情况,这样就需要服务支持幂等性,避免多次请求带来的问题。
重试取消的情况。补偿可交换原则是指Saga并行处理的过程中,如果发生了超时重试事件之后,并进行了补偿的操作,那么补偿操作是直接生效的。为了满足这个要求,需要我们在设计系统的过程中保留所有的事务数据
ACID和Saga
从上面我们可以看出,Saga只支持ACD,不提供隔离性保证。
缺乏隔离性会给我们带来以下问题:
如何应对隔离问题:
Saga的两种实现方式:
集中式的实现方式:集中式协调器负责服务调用以及事务协调
分布式的实现方式:通过事件驱动的方式进行事务的协调
集中式的Saga实现一般是通过一个Saga对象来追踪所有的Saga子任务的调用情况, 根据调用情况来决定是否需要调用对应的补偿方面,协调器和调用方是在一个进程中的。缺点就是耦合度太高。
分布式的Saga的实现使用过事件驱动的,相关的服务监听相关的事件,从而触发该服务,因此分布式Saga也叫事务编排
分布式事务的好处是:降低了耦合性以及系统的复杂性,系统的逻辑处理是基于事件。
举个具体的例子:我们现在的系统中就是基于分布式Saga处理的,我们是通过Kafka作为消息中间件,
每个服务订阅相关的Channel,当捕获相关的事件之后就自动触发服务。这里面最重要的是要持久化相关的环节,比如持久化事件信息以及中间信息,因为事务出现回滚或者补偿的时候会需要这些信息。
微服务事务的一致性建议:内刚外柔
内刚:在微服务内部通过数据库事务保证强一致性
外柔:在微服务之间的保证服务的最终一致性
参考链接:https://servicecomb.apache.org/cn/docs/distributed-transactions-saga-implementation/