分布式事务 红太狼 2021-10-13 01:13 517阅读 0赞 阅读: 深入理解分布式事务,高并发下分布式事务的解决方案 [https://blog.csdn.net/qq\_32534441/article/details/89019987][https_blog.csdn.net_qq_32534441_article_details_89019987] # 分布式事务 # 前几篇博客所介绍的事务都是基于单数据库的本地事务,目前的数据库仅支持单库事务,并不支持跨库事务。而随着微服务架构的普及,一个大型业务系统往往由若干个子系统构成,这些子系统又拥有各自独立的数据库。往往一个业务流程需要由多个子系统共同完成,而且这些操作可能需要在一个事务中完成。在微服务系统中,这些业务场景是普遍存在的。此时,我们就需要在数据库之上通过某种手段,实现支持跨数据库的事务支持,这也就是大家常说的“分布式事务”。 这里举一个分布式事务的典型例子——用户下单过程。 当我们的系统采用了微服务架构后,一个电商系统往往被拆分成如下几个子系统:商品系统、订单系统、支付系统、积分系统等。整个下单的过程如下: 1. 用户通过商品系统浏览商品,他看中了某一项商品,便点击下单 2. 此时订单系统会生成一条订单 3. 订单创建成功后,支付系统提供支付功能 4. 当支付完成后,由积分系统为该用户增加积分 上述步骤2、3、4需要在一个事务中完成。对于传统单体应用而言,实现事务非常简单,只需将这三个步骤放在一个方法A中,再用Spring的@Transactional注解标识该方法即可。Spring通过数据库的事务支持,保证这些步骤要么全都执行完成,要么全都不执行。但在这个微服务架构中,这三个步骤涉及三个系统,涉及三个数据库,此时我们必须在数据库和应用系统之间,通过某项黑科技,实现分布式事务的支持。 ## 1.CAP理论 ## CAP理论说的是:在一个分布式系统中,最多只能满足C、A、P中的两个需求。 CAP的含义: * C:Consistency 一致性 同一数据的多个副本是否实时相同。 * A:Availability 可用性 可用性:一定时间内 & 系统返回一个明确的结果 则称为该系统可用。 * P:Partition tolerance 分区容错性 将同一服务分布在多个系统中,从而保证某一个系统宕机,仍然有其他系统提供相同的服务。 CAP理论告诉我们,在分布式系统中,C、A、P三个条件中我们最多只能选择两个。那么问题来了,究竟选择哪两个条件较为合适呢? 对于一个业务系统来说,可用性和分区容错性是必须要满足的两个条件,并且这两者是相辅相成的。业务系统之所以使用分布式系统,主要原因有两个: * 提升整体性能 当业务量猛增,单个服务器已经无法满足我们的业务需求的时候,就需要使用分布式系统,使用多个节点提供相同的功能,从而整体上提升系统的性能,这就是使用分布式系统的第一个原因。 * 实现分区容错性 单一节点 或 多个节点处于相同的网络环境下,那么会存在一定的风险,万一该机房断电、该地区发生自然灾害,那么业务系统就全面瘫痪了。为了防止这一问题,采用分布式系统,将多个子系统分布在不同的地域、不同的机房中,从而保证系统高可用性。 这说明分区容错性是分布式系统的根本,如果分区容错性不能满足,那使用分布式系统将失去意义。 此外,可用性对业务系统也尤为重要。在大谈用户体验的今天,如果业务系统时常出现“系统异常”、响应时间过长等情况,这使得用户对系统的好感度大打折扣,在互联网行业竞争激烈的今天,相同领域的竞争者不甚枚举,系统的间歇性不可用会立马导致用户流向竞争对手。因此,我们只能通过牺牲一致性来换取系统的**可用性**和**分区容错性**。这也就是下面要介绍的BASE理论。 ## 2.BASE理论 ## CAP理论告诉我们一个悲惨但不得不接受的事实——我们只能在C、A、P中选择两个条件。而对于业务系统而言,我们往往选择牺牲一致性来换取系统的可用性和分区容错性。不过这里要指出的是,所谓的“牺牲一致性”并不是完全放弃数据一致性,而是牺牲**强一致性**换取**弱一致性**。下面来介绍下BASE理论。 * BA:Basic Available 基本可用 * 整个系统在某些不可抗力的情况下,仍然能够保证“可用性”,即一定时间内仍然能够返回一个明确的结果。只不过“基本可用”和“高可用”的区别是: * “一定时间”可以适当延长 当举行大促时,响应时间可以适当延长 * 给部分用户返回一个降级页面 给部分用户直接返回一个降级页面,从而缓解服务器压力。但要注意,返回降级页面仍然是返回明确结果。 * S:Soft State:柔性状态 同一数据的不同副本的状态,可以不需要实时一致。 * E:Eventual Consisstency:最终一致性 同一数据的不同副本的状态,可以不需要实时一致,但一定要保证经过一定时间后仍然是一致的。 ## 3.酸碱平衡 ## ACID能够保证事务的强一致性,即数据是实时一致的。这在本地事务中是没有问题的,在分布式事务中,强一致性会极大影响分布式系统的性能,因此分布式系统中遵循BASE理论即可。但分布式系统的不同业务场景对一致性的要求也不同。如交易场景下,就要求强一致性,此时就需要遵循ACID理论,而在注册成功后发送短信验证码等场景下,并不需要实时一致,因此遵循BASE理论即可。因此要根据具体业务场景,在ACID和BASE之间寻求平衡。 ## 4.分布式事务解决方案 ## ### 一.两阶段提交协议 2PC ### 分布式系统的一个难点是如何保证架构下多个节点在进行事务性操作的时候保持一致性。为实现这个目的,二阶段提交算法的成立基于以下假设: * 该分布式系统中,存在一个节点作为协调者(Coordinator),其他节点作为参与者(Cohorts)。且节点之间可以进行网络通信。 * 所有节点都采用预写式日志,且日志被写入后即被保持在可靠的存储设备上,即使节点损坏不会导致日志数据的消失。 * 所有节点不会永久性损坏,即使损坏后仍然可以恢复。 **1. 第一阶段(投票阶段):** 1. 协调者节点向所有参与者节点询问是否可以执行提交操作(vote),并开始等待各参与者节点的响应。 2. 参与者节点执行询问发起为止的所有事务操作,并将Undo信息和Redo信息写入日志。(注意:若成功这里其实每个参与者已经执行了事务操作) 3. 各参与者节点响应协调者节点发起的询问。如果参与者节点的事务操作实际执行成功,则它返回一个"同意"消息;如果参与者节点的事务操作实际执行失败,则它返回一个"中止"消息。 **2. 第二阶段(提交执行阶段):** 当协调者节点从所有参与者节点获得的相应消息都为"同意"时: 1. 协调者节点向所有参与者节点发出"正式提交(commit)"的请求。 2. 参与者节点正式完成操作,并释放在整个事务期间内占用的资源。 3. 参与者节点向协调者节点发送"完成"消息。 4. 协调者节点受到所有参与者节点反馈的"完成"消息后,完成事务。 如果任一参与者节点在第一阶段返回的响应消息为"中止",或者 协调者节点在第一阶段的询问超时之前无法获取所有参与者节点的响应消息时: 1. 协调者节点向所有参与者节点发出"回滚操作(rollback)"的请求。 2. 参与者节点利用之前写入的Undo信息执行回滚,并释放在整个事务期间内占用的资源。 3. 参与者节点向协调者节点发送"回滚完成"消息。 4. 协调者节点受到所有参与者节点反馈的"回滚完成"消息后,取消事务。 不管最后结果如何,第二阶段都会结束当前事务。 ![fail][] 二阶段提交看起来确实能够提供原子性的操作,但是不幸的事,二阶段提交还是有几个缺点的: 1. 执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。 2. 参与者发生故障。协调者需要给每个参与者额外指定超时机制,超时后整个事务失败。(没有多少容错机制) 3. 协调者发生故障。参与者会一直阻塞下去。需要额外的备机进行容错。(这个可以依赖后面要讲的Paxos协议实现HA) 4. 二阶段无法解决的问题:协调者再发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交。 为此,Dale Skeen和Michael Stonebraker在“A Formal Model of Crash Recovery in a Distributed System”中提出了三阶段提交协议(3PC)。 ### 二.三阶段提交协议 3PC ### 与两阶段提交不同的是,三阶段提交有两个改动点。 * 引入超时机制。同时在协调者和参与者中都引入超时机制。 * 在第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前各参与节点的状态是一致的。 也就是说,除了引入超时机制之外,3PC把2PC的准备阶段再次一分为二,这样三阶段提交就有CanCommit、PreCommit、DoCommit三个阶段。 **1. CanCommit阶段** 3PC的CanCommit阶段其实和2PC的准备阶段很像。协调者向参与者发送commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应。 1. 事务询问 协调者向参与者发送CanCommit请求。询问是否可以执行事务提交操作。然后开始等待参与者的响应。 2. 响应反馈 参与者接到CanCommit请求之后,正常情况下,如果其自身认为可以顺利执行事务,则返回Yes响应,并进入预备状态。否则反馈No **2. PreCommit阶段** 协调者根据参与者的反应情况来决定是否可以记性事务的PreCommit操作。根据响应情况,有以下两种可能。 假如协调者从所有的参与者获得的反馈都是Yes响应,那么就会执行事务的预执行。 1. 发送预提交请求 协调者向参与者发送PreCommit请求,并进入Prepared阶段。 2. 事务预提交 参与者接收到PreCommit请求后,会执行事务操作,并将undo和redo信息记录到事务日志中。 3. 响应反馈 如果参与者成功的执行了事务操作,则返回ACK响应,同时开始等待最终指令。 假如有任何一个参与者向协调者发送了No响应,或者等待超时之后,协调者都没有接到参与者的响应,那么就执行事务的中断。 1. 发送中断请求 协调者向所有参与者发送abort请求。 2. 中断事务 参与者收到来自协调者的abort请求之后(或超时之后,仍未收到协调者的请求),执行事务的中断。 **3. doCommit阶段** 该阶段进行真正的事务提交,也可以分为以下两种情况。 该阶段进行真正的事务提交,也可以分为以下两种情况。 **3.1 执行提交** 1. 发送提交请求 协调接收到参与者发送的ACK响应,那么他将从预提交状态进入到提交状态。并向所有参与者发送doCommit请求。 2. 事务提交 参与者接收到doCommit请求之后,执行正式的事务提交。并在完成事务提交之后释放所有事务资源。 3. 响应反馈 事务提交完之后,向协调者发送Ack响应。 4. 完成事务 协调者接收到所有参与者的ack响应之后,完成事务。 **3.2 中断事务** 协调者没有接收到参与者发送的ACK响应(可能是接受者发送的不是ACK响应,也可能响应超时),那么就会执行中断事务。 1. 发送中断请求 协调者向所有参与者发送abort请求 2. 事务回滚 参与者接收到abort请求之后,利用其在阶段二记录的undo信息来执行事务的回滚操作,并在完成回滚之后释放所有的事务资源。 3. 反馈结果 参与者完成事务回滚之后,向协调者发送ACK消息 4. 中断事务 协调者接收到参与者反馈的ACK消息之后,执行事务的中断。 ![3][] **优点:** 尽量保证了数据的强一致,适合对数据强一致要求很高的关键领域。(其实也不能100%保证强一致) **缺点:** 实现复杂,牺牲了可用性,对性能影响较大,不适合高并发高性能场景 ### 三.补偿事务(TCC) ### TCC 其实就是采用的补偿机制,其核心思想是:针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作。它分为三个阶段: * Try 阶段主要是对业务系统做检测及资源预留 * Confirm 阶段主要是对业务系统做确认提交,Try阶段执行成功并开始执行 Confirm阶段时,默认 Confirm阶段是不会出错的。即:只要Try成功,Confirm一定成功。 * Cancel 阶段主要是在业务执行错误,需要回滚的状态下执行的业务取消,预留资源释放。 举个例子,假入 Bob 要向 Smith 转账,思路大概是: 我们有一个本地方法,里面依次调用 1、首先在 Try 阶段,要先调用远程接口把 Smith 和 Bob 的钱给冻结起来。 2、在 Confirm 阶段,执行远程调用的转账的操作,转账成功进行解冻。 3、如果第2步执行成功,那么转账成功,如果第二步执行失败,则调用远程冻结接口对应的解冻方法 (Cancel)。 **优点:** 跟2PC比起来,实现以及流程相对简单了一些,但数据的一致性比2PC也要差一些 **缺点:** 缺点还是比较明显的,在2,3步中都有可能失败。TCC属于应用层的一种补偿方式,所以需要程序员在实现的时候多写很多补偿的代码,在一些场景中,一些业务流程可能用TCC不太好定义及处理。 ### 四、本地消息表(异步确保) ### 本地消息表这种实现方式应该是业界使用最多的,其核心思想是将分布式事务拆分成本地事务进行处理,这种思路是来源于ebay。我们可以从下面的流程图中看出其中的一些细节: ![250417-20171016141237443-2074834323.png][] 基本思路就是: 消息生产方,需要额外建一个消息表,并记录消息发送状态。消息表和业务数据要在一个事务里提交,也就是说他们要在一个数据库里面。然后消息会经过MQ发送到消息的消费方。如果消息发送失败,会进行重试发送。 消息消费方,需要处理这个消息,并完成自己的业务逻辑。此时如果本地事务处理成功,表明已经处理成功了,如果处理失败,那么就会重试执行。如果是业务上面的失败,可以给生产方发送一个业务补偿消息,通知生产方进行回滚等操作。 生产方和消费方定时扫描本地消息表,把还没处理完成的消息或者失败的消息再发送一遍。如果有靠谱的自动对账补账逻辑,这种方案还是非常实用的。 这种方案遵循BASE理论,采用的是最终一致性,笔者认为是这几种方案里面比较适合实际业务场景的,即不会出现像2PC那样复杂的实现(当调用链很长的时候,2PC的可用性是非常低的),也不会像TCC那样可能出现确认或者回滚不了的情况。 **优点:** 一种非常经典的实现,避免了分布式事务,实现了最终一致性。在 .NET中 有现成的解决方案。 **缺点:** 消息表会耦合到业务系统中,如果没有封装好的解决方案,会有很多杂活需要处理。 ### 五、MQ 事务消息 ### 有一些第三方的MQ是支持事务消息的,比如RocketMQ,他们支持事务消息的方式也是类似于采用的二阶段提交,但是市面上一些主流的MQ都是不支持事务消息的,比如 RabbitMQ 和 Kafka 都不支持。 以阿里的 RocketMQ 中间件为例,其思路大致为: 第一阶段Prepared消息,会拿到消息的地址。 第二阶段执行本地事务,第三阶段通过第一阶段拿到的地址去访问消息,并修改状态。 也就是说在业务方法内要想消息队列提交两次请求,一次发送消息和一次确认消息。如果确认消息发送失败了RocketMQ会定期扫描消息集群中的事务消息,这时候发现了Prepared消息,它会向消息发送者确认,所以生产方需要实现一个check接口,RocketMQ会根据发送端设置的策略来决定是回滚还是继续发送确认消息。这样就保证了消息发送与本地事务同时成功或同时失败。 ![250417-20171016203840240-13953078.png][] 遗憾的是,RocketMQ并没有 .NET 客户端。有关 RocketMQ的更多消息,大家可以查看[这篇博客][Link 1] **优点:** 实现了最终一致性,不需要依赖本地数据库事务。 **缺点:** 实现难度大,主流MQ不支持,没有.NET客户端,RocketMQ事务消息部分代码也未开源。 ## 最后 ## 还是那句话,能不用分布式事务就不用,如果非得使用的话,结合自己的业务分析,看看自己的业务比较适合哪一种,是在乎强一致,还是最终一致即可。 [https_blog.csdn.net_qq_32534441_article_details_89019987]: https://blog.csdn.net/qq_32534441/article/details/89019987 [fail]: /images/20211013/3250c40fd77648d1a6eb7ab074342472.png [3]: /images/20211013/2a7c9702cbd94af69a8b77d6d09ff5a4.png [250417-20171016141237443-2074834323.png]: /images/20211013/4458887defa44501baf416689f628978.png [250417-20171016203840240-13953078.png]: /images/20211013/eb1a8e482c764ae5bbd0177341b656de.png [Link 1]: http://www.jianshu.com/p/453c6e7ff81c
相关 【分布式事务】分布式事务Seata 文章目录 前言 什么是分布式事务? (1)数据库分库分表就产生了分布式事务; (2)项目拆分服务化也产生了分布式事务; 一、W 客官°小女子只卖身不卖艺/ 2023年10月09日 13:49/ 0 赞/ 72 阅读
相关 分布式事务(二)分布式事务方案 文章目录 什么是分布式事务 理论部分 CAP BASE 分布式事务方案 什么是分布式事务 首先这是普通事务: ![ 太过爱你忘了你带给我的痛/ 2023年02月28日 01:29/ 0 赞/ 10 阅读
相关 分布式-分布式事务 分布式事务 文章目录 分布式事务 一,本地消息表 二,2PC 两阶段提交 三,3PC 三段式提交 四,T 待我称王封你为后i/ 2022年11月27日 15:40/ 0 赞/ 334 阅读
相关 分布式事务01-分布式事务概述 文章目录 1.分布式事务产生的背景 1.1 分布式事务在不同场景下如何产生 1.2 案例 2.事务理论知识 2.1 AC 旧城等待,/ 2022年04月25日 09:54/ 0 赞/ 396 阅读
相关 分布式事务 一、前言 在单个数据库实例时候,我们可以使用一个数据源的事务([本地事务][Link 1] )来保证事务内的多个操作要么全部执行生效,要么全部不生效。在多数据库实例节点时 冷不防/ 2022年04月14日 02:09/ 0 赞/ 411 阅读
相关 分布式事务 什么是分布式事务 分布式事务涉及到操作多个数据库的事务,分布式事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于分布式系统的`不同节点上`。一个分布式事务可 Dear 丶/ 2022年03月10日 15:27/ 0 赞/ 286 阅读
相关 分布式事务 1、分布式事务产生的背景 在微服务环境下,因为会根据不同的业务会拆分成不同的服务,比如会员服务、订单服务、商品服务等,让专业的人做专业的事情,每个服务都有自己独立的数据库,并 - 日理万妓/ 2021年10月25日 14:09/ 0 赞/ 492 阅读
相关 分布式事务 阅读: 深入理解分布式事务,高并发下分布式事务的解决方案 [https://blog.csdn.net/qq\_32534441/article/details/890 红太狼/ 2021年10月13日 01:13/ 0 赞/ 518 阅读
相关 分布式事务 在分布式系统中,为了保证数据的高可用,通常,我们会将数据保留多个副本(replica),这些副本会放置在不同的物理的机器上。为了对用户提供正确的 CRUD 等语义,我们需... 灰太狼/ 2020年04月24日 17:42/ 0 赞/ 990 阅读
还没有评论,来说两句吧...