【高并发】- 分布式事务都不会?

前言

    本章主要对分布式事务进行梳理和讲解。可能在业务设计过程中,各微服务都采用了独立数据库,所以,这些微服务之间的数据共享有了更高的要求:要解决数据一致性的问题。

1. 数据一致性

    数据一致性是指:数据被多次操作或者以多种方式操作时,能保持业务的不变性。数据一致性存在于很多场景中。导致数据不一致的原因也不尽相同。

  • 在对数据库中的内容进行读写时,不是每个用户都能读取到正确的数据,可能在读取时数据未同步过来。

  • 在分布式系统中,在Leader节点的“写”数据同步到各个Slave节点时,如果有一个节点未同步,则会造成数据不一致。

  • 在多个业务方对同一个数据源获取数据时,如果业务方没有核对数据就进行相关计算,则会因为不同业务方使用了不同的处理逻辑,从而导致多个业务方最终的结果数据不一致。

  • 在使用缓存的场景中,缓存更新策略的不同会造成缓存与数据库的数据不一致。

场景:

    对于数据一致性问题,很典型的案例就是银行转账:在双方转账前后,双方的余额总和应该是不变的,这就是数据一致性。例如账户A向账户B转了100元:

  • 如果转账成功,则账户A扣掉100元,账户B增加100元。

  • 如果转账失败,则双方账户余额保持不变。

    这就是数据一致性的具体表现。如果账户A的余额变少了,而账户B的余额没有增加,则数据是不一致的。

2. 数据库事务保证数据一致性

    数据一致性的根本问题是如何保证操作的原子性。在关系型数据库中,可以利用其ACID(Atomic、Consistency、Isolation、Durability)特性来保证原子操作,即在同一个事务内的操作都是原子性的,所有操作要么都成功,要么都失败。只要事务被提交了,即使机器宕机了,数据都是一致的。

下面来分析一下关系型数据库的ACID特性:

  • Atomic(原子性):事务中的所有语句要么都成功,要么都失败,只要其中一条语句失败,就会回滚整个事务,不会出现“更新了其中一张表,而没有更新其他表”的情况。

  • Consistency(一致性):事务总是从一个有效状态转移到另一个有效状态,即它保证读取的数据总是一致的。

  • Isolation(隔离性):在一个事务中,所做的任何操作,在未提交前,其对其他事务都是不可见的。事务是互相隔离的,自己运行自己的,互不影响。

  • Durability(持久性):只要事务提交成功了,数据的所有修改就会持久化到磁盘中,即使宕机也不会造成数据的丢失或改变。

(在很多场景中采用数据库事务来解决数据的一致性问题。一般编程框架都支持数据库事务,例如在Spring框架中使用注解@Transactional来开启事务,其中的所有操作属于同一个事务。)

3. 分布式事务

    前面介绍了通过数据库事务来保证数据的一致性,但很多公司中,都是由多个系统协作处理且涉及多个数据库的操作,用单一数据库事务很难解决数据一致性的问题。

    有这样一种场景:分布式系统被分为多个系统,这些系统在不同的计算机进程中运行,且每个系统都有自己独立的数据库,一次请求操作会在这几个数据库中进行更新。这个场景比前面说的单数据库事务复杂太多。所以,接下来分析在分布式系统环境如何利用分布式事务来解决分布式系统的数据一致性问题。

(分布式事务也是事务,只不过它是在分布式系统中的事务。分布式事务由多个本地食物组合而成,其基本满足ACID特性)

    随着分布式系统越来越复杂,为了满足系统的高性能及高可用,分布式系统是不完全满足ACID特性的。目前实现分布式事务的解决方案有如下几种:

  • 基于XA协议的二阶段提交。

  • 基于XA协议的三阶段提交。

  • TCC。

  • 基于消息的最终一致性。

每一种分布式事务解决方案都有各自擅长的场景:

  • 基于XA协议的二阶段和基于XA协议的三阶段提交方案,只针对强一致性,遵从ACID特性。

  • TCC方案,适合作用在服务层,不与具体的服务框架耦合。

  • 基于消息的最终一致性方案是针对最终一致性的,遵从BASE理论。

    在企业系统日常开发中,基于XA协议的二阶段提交和基于消息的最终一致性方案较多。下面就看下这两种分布式事务方案:

(1)基于XA协议的二阶段提交

    “二阶段提交”中的“二阶段”指准备阶段和提交阶段。为了保证分布在不同节点上的事务保持一致,在“基于XA协议的二阶段提交”中引入了“事务协调者”的角色,通过它来保证各个事务被正确提交,如果提交失败则回滚所有事务。

  • 在第一阶段(即准备阶段)中,“事务协调者”会向所有“事务参与者”发送“准备”指令,然后等待“事务参与者”的回复。“事务参与者”在收到“准备”指令后,就各自进行自己的业务处理,除提交事务的所有动作(包括开启本地事务和逻辑处理等)外,还要记录操作的事务日志。如果执行成功,则“事务参与者”向“事务协调者”回复“已准备完成”的消息;如果在执行过程中出现失败或者超时,则“事务参与者”向“事务协调者”发送“准备失败”的消息。

  • 在第二阶段(即提交阶段)中,“事务协调者”依据“事务参与者”在第一阶段返回的消息执行相应的操作:如果都是“已准备完成”,则发送“提交指令”给“事务参与者”,“事务参与者”继续完成之前剩下的真正事务提交动作;如果有“事务参与者”返回“准备失败”的消息,则向所有“事务参与者”发送“回滚”指令,然后所有“事务参与者”回滚第一阶段中的所有操作。

(只有当“事务协调者”收到所有“事务参与者”回复的“提交成功”消息,才表示整个分布式事务结束了)

    以订单系统和库存系统下单扣减库存为例,感受一下二阶段提交是如何保证分布式事务一致性的。

    在第一阶段中,“事务协调者”向订单系统和库存系统发送“准备”指令。订单系统完成自己的创建订单相关动作,完成后,不提交实物,只是向“事务协调者”回复“已准备完成”的消息。库存系统完成自己的扣减库存动作,在完成后不提交事务,只是向“事务协调者”回复“已准备完成”的消息。

    在第一阶段中,“事务协调者”收到了订单系统及库存系统“已准备完成”的消息。

    接下来进入第二阶段,“事务协调者”向订单系统和库存系统发送“提交”指令,然后,订单系统提交创建订单的事务,库存系统提交扣减库存的事务,接着各自都向“事务协调者”发送“提交成功”的消息:

    只要其中一个过程失败,则整个事务回滚,回到所有系统之前的状态。例如,在扣减库存时出现库存不足

    二阶段提交算法是一种强一致性设计,适用于对数据一致性要求很高的场景,但是它也有一些缺陷,例如:

  • 每个节点都是事务阻塞的,这样对于并发很多的请求就会出现吞吐率下降的情况。

  • “事务协调者”是单点的,有不可用的风险。

(2)基于消息的最终一致性。

    可以利用消息中间件(如RocketMQ)来达到数据的最终一致性。

    以“浏览商品并将商品加入购物车,然后进入购物车下单”的流程为例,来分析如何使用消息中间件来达到数据 的最终一致性。

    场景:订单系统创建一个新的订单信息,然后购物车系统删除已存在于订单中的商品。

① 订单系统创建订单消息,并将其发送给RocketMQ,此时消息状态为“待确认”。

② 订单消息在RocketMQ中被持久化存储,存储消息状态为“待发送”。

③ 如果消息被持久化成功,则订单系统开始创建订单;如果失败,则放弃创建订单。

④ 订单系统在创建完订单后,将创建订单成功的消息发送给RocketMQ。

⑤ RocketMQ收到创建订单成功的消息,然后将消息状态设置为“可发送”,接着,RocketMQ将当前创建订单成功的消息发送给购物车系统。

⑥ 购物车系统在获取创建订单成功的消息后,删除购物车中的商品。

⑦ 购物车系统在完成自己的操作后,通知ROcketMQ将当前创建订单成功的消息改为“已完成”状态。

    在分布式系统场景中,只有系统中所有节点事务都成功,整个分布式事务才算成功。目前还没有一种既简单又完美的方案来应对所有场景,需要根据实际业务去做相应的取舍。

    本章主要介绍了分布式事务管理的思想和设计方案,小伙伴们需要根据自己所在公司的业务场景,制定合适的技术落地方案,确保业务是符合公司业务场景需要的。

    下一章开始,会讲解生成级系统框架设计的细节,第一章会讲幂等性的设计及思路。希望有兴趣的小伙伴能够转发和分享

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在高并发场景下,分布式事务是必须的。在选择分布式事务时,需要考虑以下几个方面: 1. 数据一致性:分布式事务需要保证不同节点之间的数据一致性,因此需要选择一种能够保证数据一致性的分布式事务方案,如 2PC(两阶段提交协议)或 3PC(三阶段提交协议)、TCC(补偿事务)等。 2. 性能:分布式事务需要涉及到多个节点之间的通信和协调,因此需要选择一种性能较好的分布式事务方案,如基于消息队列的分布式事务、异步事务等。 3. 可扩展性:在分布式系统中,需要考虑系统的可扩展性,因此需要选择一种能够支持水平扩展的分布式事务方案,如基于分库分表的分布式事务。 4. 容错性:在分布式系统中,需要考虑节点故障的情况,因此需要选择一种能够保证容错性的分布式事务方案,如基于 Paxos 或 Raft 算法的分布式事务。 综上所述,分布式事务的选择需要综合考虑以上几个方面,选择一种适合自己业务场景的分布式事务方案,以保证系统的稳定性和可靠性。 ### 回答2: 在高并发场景下,分布式事务的选择是非常重要的。高并发场景通常由大量的用户请求和复杂的业务逻辑组成,需要保证系统的稳定性和数据的一致性。以下是几种常见的分布式事务选择: 1. 两阶段提交(2PC):这是一种经典的分布式事务协议,它通过协调者和参与者之间的消息进行事务的提交,保证分布式系统中所有节点的一致性。然而,2PC存在单点故障和阻塞问题,同时在网络不稳定的情况下可能导致长时间的等待,不适合高并发场景的使用。 2. TCC(Try-Confirm-Cancel):TCC是一种基于补偿的分布式事务解决方案,它将事务拆分为三个阶段(试验、确认、取消)。在高并发场景下,TCC通过使用乐观锁或幂等性操作来解决并发冲突的问题,提供较好的性能和可伸缩性。 3. 本地消息表:在高并发场景下,将分布式事务转变为本地事务,使用本地消息表来实现事务的异步化和解耦。通过将事务操作记录插入本地消息表,并使用消息队列来异步处理事务,可以提高系统的吞吐量和并发处理能力。 4. Saga模式:Saga模式是一种面向分布式事务的异步解决方案,它将复杂的分布式事务拆分为一系列的局部事务。每个局部事务通过记录其提交和补偿操作,以保证系统的一致性。在高并发场景下,Saga模式具有较好的性能和可伸缩性,但需要更多的系统设计和开发工作。 综上所述,在高并发场景下,选择适合的分布式事务解决方案是非常重要的。根据具体的业务需求和系统特点,我们可以选择2PC、TCC、本地消息表或Saga模式等解决方案,来保证系统的稳定性和数据的一致性。最终的选择应该综合考虑系统性能、可伸缩性和开发成本等因素。 ### 回答3: 高并发场景下的分布式事务选择是一个比较复杂的问题,需要综合考虑系统的性能、一致性和可靠性等多个因素。 在高并发场景下,传统的单机事务往往无法满足要求,因此需要采用分布式事务来处理大量并发请求。目前主流的分布式事务解决方案有两种:基于两阶段提交(2PC)协议和基于消息队列的异步处理。 基于2PC协议的分布式事务是传统的解决方案,通过事务协调者协调各个参与者的事务操作,实现分布式事务的一致性。但是2PC存在的问题是性能低下和可靠性不高。2PC协议需要进行同步的预提交、提交和回滚等操作,整个流程需要等待所有参与者的响应,这会导致事务的响应时间长,并发能力受到限制。同时,2PC的串行执行也对系统的可靠性提出了较高要求,一旦协调者宕机,整个事务将无法进行。 基于消息队列的异步处理是一种新的解决方案,它将事务操作封装为消息,通过消息队列来进行异步处理。参与者将事务消息发送至消息队列,由消息队列异步处理消息,保证事务的可靠性和一致性。通过将事务操作异步化,可以大大提高系统的并发能力和性能。而且,基于消息队列的解决方案对系统的可靠性要求较低,即使消息队列宕机,事务消息也可以通过存储进行恢复。 综上所述,在高并发场景下,基于消息队列的异步处理是更好的分布式事务选择。它能够提供较好的性能和可靠性,适应大规模并发的需求。但需要注意的是,选择分布式事务方案时需要根据实际需求综合考量各种因素,目前还有其他的解决方案,如基于补偿事务和Saga模式等,可以根据具体情况进行选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值