通过关系型数据库来控制事务,这是利用数据库本身的事务特性来实现的,因此叫数据库事务,由于应用主要靠关系数据库来控制事务,而数据库通常和应用在同一个服务器,所以基于关系型数据库的事务又被称为本地事务。
数据库事务的四大特性ACID:
一般来说AD由日志文件来完成,CI由锁来完成
分布式事务指事务的操作位于不同的节点上,因此需要服务与服务之间远程协作才能完成事务操作,这种分布式系统环境下由不同的服务之间通过网络远程协作完成事务称之为分布式事务,例如:
讲人话:
如在商城系统中,用户在下单时,创建订单和扣减库存,需要同时对订单DB和库存DB进行操作。两步操作必须同时成功,否则就会造成业务混乱,可此时我们只能保证自己服务的数据一致性,无法保证调用其他服务的操作是否成功,所以为了保证整个下单流程的数据一致性,就需要分布式事务介入。
1998年,加州大学的计算机科学家 Eric Brewer 提出,分布式系统有三个指标。这三个指标不可能同时做到。这个结论就叫做 CAP 定理。
C:Consistency(强一致性):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)。主从一致性会削弱可用性。
A:Availability(可用性):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
P:Partition tolerance(分区容错性):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。说白了同一时间从集群中拿到两种结果;
CAP理论就是说在分布式存储系统中,最多只能实现上面的两点。
因为只要有网络交互就一定会有延迟和数据丢失,这种状况我们必须接受,必须保证系统不能挂掉。所以分区容忍性 P 是我们必须需要实现的。
所以我们只能在一致性和可用性之间进行权衡
因此,根据 CAP 原理将 NoSQL 数据库分成了满足 CA 原则、满足 CP 原则和满足 AP 原则三 大类:
CA - 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。
CP - 满足一致性,分区容忍必的系统,通常性能不是特别高。
AP - 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。
BASE就是为了解决关系数据库强一致性引起的问题而引起的可用性降低而提出的解决方案。
BASE其实是下面三个术语的缩写:
基本可用(Basically Available)分布式系统在出现故障时,允许损失部分可用性,即保证核心可用。
软状态(Soft state)在一定时间内,允许出现中间状态,比如临时的不一致状态。
最终一致(Eventually consistent)虽然无法保证强一致性,但是在软状态结束后,最终达到数据一致。
它的思想是通过让系统放松对某一时刻数据一致性的要求来换取系统整体伸缩性和性能上改观。为什么这么说呢,缘由就在于大型系统往往由于地域分布和极高性能的要求,不可能采用分布式事务来完成这些指标,要想获得这些指标,我们必须采用另外一种方式来完成,这里BASE就是解决这个问题的办法
分布式事务最大的问题是各个子事务的一致性问题,因此可以借鉴CAP定理和BASE理论,有两种解决思路:
AP模式:各子事务分别执行和提交,允许出现结果不一致,然后采用弥补措施恢复数据即可,实现最终一致。
CP模式:各个子事务执行后互相等待,同时提交,同时回滚,达成强一致。但事务等待过程中,处于弱可用状态。
但不管是哪一种模式,都需要在子系统事务之间互相通讯,协调事务状态,也就是需要一个事务协调者(TC):
XA协议是一个基于数据库的分布式事务协议,其分为两部分:事务管理器和本地资源管理器。
事务管理器作为一个全局的调度者,负责对各个本地资源管理器统一号令提交或者回滚。
二阶提交协议(2PC)和三阶提交协议(3PC)就是根据此协议衍生出来而来。
如今Oracle、Mysql等数据库均已实现了XA接口。
2PC(Two-phase commit protocol) 二阶段提交协议,属于数据强一致性的解决方案,引入了事务管理器Transaction Manager、事务参与者Resource Manager的概念,分为准备阶段prepare phase,提交阶段commit phase
准备阶段: 事务协调者向每个参与者发送prepare请求,每个事务参与者执行本地事务,写入undo/redo日志,不执行提交操作
提交阶段: 事务管理器收到任意一个事务参与者的失败或者超时响应时,向每个事务参与者发送回滚请求;反之向所有参与者发送提交请求。参与者收到事务管理器的指令执行提交或者回滚操作,并释放事务处理中使用到的锁资源。必须在最后阶段释放锁资源
拿电商系统中,第三方支付给我们的支付系统,然后支付系统调用订单系统更改订单状态为例
1 阶段
阶段一:提交事务请求
-事务询问
协调者节点向所有参与者节点询问是否可以执行提交操作(vote),并开始等待各参与者节点的响应。
-执行事务
参与者节点执行询问发起的所有事务操作,并将Undo信息和Redo信息写入日志。(注意:若成功这里其实每个参与者已经执行了事务操作)
-各参与者向协调者反馈事务询问的响应
各参与者节点响应协调者节点发起的询问。如果参与者节点的事务操作实际执行成功,则它返回一个”同意”消息;如果参与者节点的事务操作实际执行失败,则它返回一个”中止”消息。
2 阶段
阶段二:执行事务提交
当协调者节点从所有参与者节点获得的相应消息都为”同意”时:
发送提交请求
协调者节点向所有参与者节点发出”正式提交(commit)”的请求。
事务提交
参与者节点正式完成操作,并释放在整个事务期间内占用的资源。
反馈事务提交结果
参与者节点向协调者节点发送”完成”消息。
如果任一参与者节点在第一阶段返回的响应消息为”中止”,或者 协调者节点在第一阶段的询问超时之前无法获取所有参与者节点的响应消息时:
中断事务:
发起回滚请求
协调者节点向所有参与者节点发出”回滚操作(rollback)”的请求。
事务回滚
参与者节点利用之前写入的Undo信息执行回滚,并释放在整个事务期间内占用的资源。
反馈事务回滚结果
参与者节点向协调者节点发送”回滚完成”消息。
中断事务
协调者节点受到所有参与者节点反馈的”回滚完成”消息后,取消事务。
不管最后结果如何,第二阶段都会结束当前事务。
2PC是一种尽量保证强一致性的分布式事务,因此它是同步阻塞的,而同步阻塞就会导致长久的资源锁定问题,效率较低;且存在单点问题,协调者出现问题后,在极端情况下存在数据不一致的风险。
三段提交(3PC)是对两段提交(2PC)的一种升级优化,3PC在2PC的第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前,各参与者节点的状态都一致。同时在协调者和参与者中都引入超时机制,当参与者各种原因未收到协调者的commit请求后,会对本地事务进行commit,不会一直阻塞等待,解决了2PC的单点故障问题,但3PC 还是没能从根本上解决数据一致性的问题。
CanCommit:协调者向所有参与者发送CanCommit命令,询问是否可以执行事务提交操作。如果全部响应YES则进入下一个阶段。
PreCommit:协调者向所有参与者发送PreCommit命令,询问是否可以进行事务的预提交操作,参与者接收到PreCommit请求后,如参与者成功的执行了事务操作,则返回Yes响应,进入最终commit阶段。一旦参与者中有向协调者发送了No响应,或因网络造成超时,协调者没有接到参与者的响应,协调者向所有参与者发送abort请求,参与者接受abort命令执行事务的中断。
DoCommit:在前两个阶段中所有参与者的响应反馈均是YES后,协调者向参与者发送DoCommit命令正式提交事务,如协调者没有接收到参与者发送的ACK响应,会向所有参与者发送abort请求命令,执行事务的中断。
区别:
1、引入超时机制。同时在协调者(超时,中断事务)和参与者(超时,在pre中断,在 do 提交)中都引入超时机制。
2、在第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前各参与节点的状态是一致的。
3、3pc解决了2pc单点故障的问题,并减少阻塞,即减少了锁定的时间
4、但是3pc并不能解决2pc的问题,只是降低灾难发生的概率
TCC和2pc、3pc一样也是一种分布式的方案设计。TCC(Try-Confirm-Cancel)又被称补偿事务。但2PC 是应用于在DB层面,TCC则可以理解为在应用层面的2PC,是需要我们编写业务逻辑来实现。
我们可以考虑这个问题,2pc/3pc都只能解决数据库的回滚,但是如果在某个服务中写入了io文件,或者在redis中产生了数据,那就无法回滚了,这是后TCC就杀出来了;
Try阶段:
完成对应的事务操作
Confirm阶段:
当事务操作成功后走这个阶段
Cancel阶段:
当事务操作失败后,走这个操作,此时我们可以在此写相关事务操作的逆操作。如事务是insert,那这里我就delete。事务是产生了一个文件,这里我就直接删除了这个问题。
CC的缺点:
应用侵入性强:TCC由于基于在业务层面,至使每个操作都需要有 try、confirm、cancel三个接口。
开发难度大:代码开发量很大,要保证数据一致性 confirm 和 cancel 接口还必须实现幂等性。
上面讲的是分布式事务解决的理论设计,那么在此我们根据上述设计方案,提供市面上的常用解决方案和框架使用。
Lock(锁定事务单元),Confirm(确认事务),Notify(通知事务)
协调者称之为TxManager , 参与者称之为 TxClient
lcn官网:https://www.codingapi.com/docs/txlcn-setting-manager/
lcn模式是基于2pc阶段创建的框架,
代码实现:我稍后放在同专栏的另一篇博客
分布式事务-TX-LCN 的lcn模式和tcc模式
TCC事务机制相对于传统事务机制(X/Open XA Two-Phase-Commit),其特征在于它不依赖资源管理器(RM)对XA的支持,而是通过对(由业务系统提供的)业务逻辑的调度来实现分布式事务。主要由三步操作,Try: 尝试执行业务、 Confirm:确认执行业务、 Cancel: 取消执行业务。
代码实现:我稍后放在同专栏的另一篇博客
分布式事务-TX-LCN 的lcn模式和tcc模式
Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。AT模式是阿里首推的模式,阿里云上有商用版本的GTS(Global Transaction Service 全局事务服务)。
在Seata的架构中,一共有三大角色:
TC(Transaction Coordinator)- 事务协调者
维护全局和分支事务的状态,驱动全局事务提交或回滚。
TM(Transaction Manager)- 事务管理器
定义全局事务的范围:开始全局事务、提交或回滚全局事务,当然他也是一个RM
RM(Resource Manager)- 资源管理器
官网文档:https://seata.io/zh-cn/docs/overview/what-is-seata.html
两阶段提交协议的演变:
一阶段:
二阶段:
详细介绍在我的另一篇博客:分布式事务-seata 的AT模式和tcc模式
AT 模式(参考链接 TBD)基于 支持本地 ACID 事务 的 关系型数据库:
一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。
二阶段 commit 行为:马上成功结束,自动 异步批量清理回滚日志。
二阶段 rollback 行为:通过回滚日志,自动 生成补偿操作,完成数据回滚。
相应的,TCC 模式,不依赖于底层数据资源的事务支持:
一阶段 prepare 行为:调用 自定义 的 prepare 逻辑。
二阶段 commit 行为:调用 自定义 的 commit 逻辑。
二阶段 rollback 行为:调用 自定义 的 rollback 逻辑。
所谓 TCC 模式,是指支持把 自定义 的分支事务纳入到全局事务的管理中
详细介绍在我的另一篇博客:分布式事务-seata 的AT模式和tcc模式
这种方案是基于分布式服务理论从业务层面做出的设计,【消息队列+本地事件表】方案就是消息队列搭配上本地事件表实现的分布式事务,这种方案的特点就是通过服务和消息队列的整合,可以对服务实现解耦,缺点是异步执行
详细介绍在我的另一篇博客:
分布式事务讲解 -消息队列+定时任务+本地事件表
最大努力通知是当我们作为第三方服务对外暴露服务时,我们可以可以使用此方法,并且此方法已经多次应用在支付宝,微信等方案中;
此方案主要由两个特点:
此方案是对方案方案3的进一步优化
他可以靠我们自己开发一套可靠的消息服务将之前的定时任务和事件表通过一个单独的服务来解耦;
这样每个服务就可以只关注自己的业务实现,比如支付服务只需要把消息传给可靠消息服务就完成了,可靠消息服务可以通过自己的一系列开发将消息传给mq
利用recketmq的消息发送机制(只要不发送commit),mq就可以一直回调查询事务状态。
这个方案是可靠消息服务方案的升级版,相当于把我们自己曾经做的服务完全交给了recketmq。
详细开发在我的另一篇博客里:分布式事务-事务消息模型/消息最终一致性
虽然分布式事务的解决方案有很多,但是就像CAP理论一样,每套方案都有自己的优点和缺点。
技术是为业务服务的。不要为了技术而技术。
最后建议大家,如果可以通过业务处理,尽量不要使用分布式事务,白白给自己增加工作量。
最后的最后,给大家分享一个鸵鸟算法。自己体会吧:
在计算机科学中,鸵鸟算法是一个忽略潜在问题的一种算法策略,这种策略对计算机程序可能出现的问题采取无视态度(类似于鸵鸟在遇到危险时将头埋在地里,装作看不见)。鸵鸟算法的使用前提是,问题出现的概率很低
就像cap理论一样,基于现有的科技体系,有些问题就是无法解决。就不要强求了。前提是这些问题发生的概率非常非常低!