探讨分布式事务的解决方案

分布式事务常用的解决方案有几种呢?大概四种吧,这让我想起鲁迅先生的一篇著名短篇小说《孔乙己》。

在《孔乙己》的故事中,孔乙己因为会写四种不同的“回”字而自豪,是不是也和今天我知道分布式事务常用的解决方案有四种一样呢?

我想,还是有不同吧。

孔乙己会写四种不同的“回”字只能用来考试。

而学习分布式事务常用的解决方案,除了考试以外,还能在实际工作中用到,并且通过这些技术来开发出更强大的系统,让更多的人受益。

书归正传

常用的四种基于分布式事务

  1. 两段提交协议(2PC,Two-Phase Commit)

    • 2PC 是一种经典的分布式事务协议。它通过协调者(通常是一个事务管理器)来保证事务的一致性。2PC 分为两个阶段:
      • 准备阶段:协调者询问所有参与者是否准备好提交事务。
      • 提交阶段:如果所有参与者都准备好,则提交事务;否则,回滚事务。
    • 缺点:2PC 在遇到网络故障或节点崩溃时可能导致数据不一致,且没有回滚机制,因此不适用于高并发的场景。
  2. 三段提交协议(3PC,Three-Phase Commit)

    • 3PC 是对 2PC 的改进,通过引入一个中间阶段,降低了部分失败情况下的阻塞问题。
      • 准备阶段:协调者询问所有参与者是否准备好提交事务。
      • 预提交阶段:参与者确认准备好并进入预提交状态。
      • 提交阶段:如果所有参与者都确认预提交,则协调者提交事务。
    • 优点:相比 2PC,3PC 增强了容错性,但依然存在网络分区问题。
  3. 最终一致性(Eventual Consistency)

    • 在某些场景中,分布式事务的目标不是立即一致性,而是通过一段时间内的异步操作,最终达到一致性。这种模式通常适用于大规模分布式系统,如微服务架构中的事件驱动架构。
    • 优点:允许系统在短时间内处于不一致的状态,但通过后台补偿机制和重试机制最终达到一致。
    • 缺点:在某些应用场景中,这种最终一致性可能会导致短期内的数据不一致,可能影响用户体验。
  4. 补偿事务(Saga模式)

    • Saga 模式通过将一个大的分布式事务拆分成多个子事务,每个子事务都在独立的服务中执行。当一个子事务失败时,通过执行补偿操作来回滚之前成功执行的事务,从而保证系统的最终一致性。
    • 分为两种类型
      • 编排式 Saga:由一个中央协调者来控制事务的流程,负责决定每个步骤的执行。
      • 微服务式 Saga:每个服务自主执行,彼此间通过消息传递来通知。
    • 优点:不会阻塞系统,适用于长事务,可以高效地处理大量的分布式事务。
    • 缺点:设计和实现较为复杂,补偿操作可能增加开发负担。

2PC 协议详细说明

2PC 协议是分布式事务中的一种经典协议,旨在保证分布式系统中各参与节点的一致性。它分为两个阶段:准备阶段和提交阶段。虽然2PC在很多场景下能确保事务的一致性,但在遇到网络故障或节点崩溃时,可能会导致数据不一致。

1. 2PC 协议的基本流程

  • 第一阶段(准备阶段)
    • 协调者向所有参与者发出请求,询问它们是否准备好提交事务。
    • 每个参与者要么提交事务(答应准备好),要么因某些原因拒绝事务(返回“拒绝”)。
  • 第二阶段(提交阶段)
    • 如果所有参与者都同意提交事务,协调者会向各个参与者发送“提交”命令。
    • 如果有任何一个参与者拒绝提交,协调者则会发送“回滚”命令。

2. 发生网络故障或节点崩溃时可能出现的问题

2.1 协调者崩溃
  • 如果协调者(事务管理器)在准备阶段或提交阶段崩溃,会导致所有参与者不知道事务是否应该提交或回滚。
  • 具体情形
    • 假设协调者在准备阶段询问所有参与者是否准备好提交,但在收到部分参与者的响应后崩溃。
    • 由于协调者没有完成提交或回滚的决策,参与者不知道该执行提交操作还是回滚操作。它们必须等待协调者重新启动并告知决策,这可能导致事务长时间挂起,甚至最终无法恢复。
  • 问题总结:由于协调者的崩溃,参与者无法知道事务的最终决定,可能导致事务卡住,甚至出现不一致。
2.2 参与者崩溃
  • 如果某个参与者在准备阶段崩溃,它可能没有机会响应协调者的请求,也没有机会完成事务的提交或回滚。
  • 如果参与者在提交阶段崩溃,可能已经接受了提交请求,但由于没有返回确认消息,协调者不知道事务是否已经成功提交。
  • 具体情形
    • 假设参与者在准备阶段回答了“准备提交”,但在收到提交命令之前崩溃。恢复后,参与者不知道该做什么,是继续提交,还是回滚。此时,协调者可能已经提交了事务,但这个参与者仍然处于未知状态。
  • 问题总结:由于参与者的崩溃,它的状态变得不明确,这会导致事务的不一致。
2.3 网络分区
  • 如果在准备阶段或提交阶段,网络出现分区,导致某些参与者与协调者失去联系,但其他参与者仍然与协调者保持通信,那么会出现部分参与者提交,部分参与者回滚的情况。
  • 具体情形
    • 假设在准备阶段,某些参与者收到协调者的“准备提交”请求并回复,但网络故障导致协调者未能接收到部分参与者的回复。
    • 如果协调者此时崩溃或无法与未接收到回复的参与者恢复连接,它可能会做出错误的决定(例如,提交或回滚),导致系统处于不一致状态。
  • 问题总结:网络分区导致部分参与者无法正常通信,协调者不能获得全体参与者的状态信息,最终可能导致事务不一致。

3. 没有回滚机制的问题

  • 2PC 协议的一个关键问题是它没有提供自动回滚机制。回滚只能在协调者收到所有参与者的失败反馈后触发。
  • 如果参与者在准备阶段同意提交,但在事务提交前崩溃,协调者不能主动决定如何回滚已提交的事务。
  • 具体情形
    • 假设一个参与者在准备阶段答应提交,之后由于某些原因崩溃,未能收到提交命令。协调者可能会继续等待,直到恢复后才知道状态,但此时可能已经出现部分提交或状态不一致的问题。即使协调者回滚事务,也无法完全撤销已提交的部分操作。

4. 总结:为什么 2PC 不适用于高并发场景

  • 阻塞问题:在 2PC 中,如果有任何节点发生故障,所有其他节点都将被阻塞,直到协调者恢复并做出决定。这种等待可能会影响系统的响应时间,导致系统整体性能下降,尤其在高并发场景中,这种阻塞效应更加明显。
  • 长时间持锁:为了确保事务的一致性,2PC 协议可能导致锁长时间占用,尤其是在网络不稳定或故障恢复时,参与者或协调者的长时间等待会严重影响系统的吞吐量和响应速度。
  • 一致性问题:由于节点崩溃或网络故障,系统可能进入不一致状态,且很难在没有额外的机制(如重试、补偿等)的情况下恢复。

因此,2PC 协议适用于网络稳定和事务量较少的场景,而在高并发、长事务或网络不稳定的环境下,使用 2PC 协议可能导致性能瓶颈和数据不一致。

为什么三段提交协议优于二段提交协议?

“三段提交协议”的好处包括:

  1. 提高系统可靠性: 通过三阶段的过程(准备阶段、提交阶段、确认阶段),协议确保每个参与节点都可以在操作过程中确认是否可以安全地提交数据,避免了因为部分节点失败而导致的系统状态不一致的问题。

  2. 避免数据丢失: 三段提交协议通过预先的“准备”阶段确认所有参与者都能接受事务操作,从而避免了在事务提交过程中因为网络或节点故障导致的数据丢失,确保了数据的一致性。

  3. 减少分布式事务中的不一致性: 在传统的两段提交协议中,如果在提交操作过程中发生故障,可能会导致部分节点提交了事务,而另一些节点没有提交,造成系统的数据不一致。而三段提交协议通过增加一个“确认”阶段,确保只有在所有节点都确认事务能够安全提交后,才会最终执行提交操作,减少了不一致的风险。

  4. 更好地处理节点故障: 通过三阶段的过程,如果一个节点发生故障,它可以通过“准备”阶段的投票机制及时发现问题并采取适当的补救措施,例如回滚事务或等待故障恢复,避免了事务被错误地提交到不完整或损坏的数据上。

  5. 支持长时间事务: 三段提交协议支持跨多个节点的长时间事务,确保即使某个节点需要更长时间进行处理,整个事务也能保持一致性并按照预定规则完成。

  6. 灵活的事务管理: 三段提交协议增加了事务的灵活性,参与节点可以在不同阶段做出决策,允许系统根据不同条件进行调整和优化,进一步提升了系统的健壮性和容错能力。

为什么淘宝可以使用最终一致性而不怕订单不一致?

  1. 高可用性和容错设计: 淘宝作为一个全球范围的大型电商平台,需要应对海量的并发请求、网络延迟和潜在的节点故障。如果在每次用户下单、支付等操作时都要求强一致性(即每个操作后立刻同步到所有节点),那么即使是网络延迟或节点故障都会导致系统性能下降,影响用户体验。因此,淘宝采用了最终一致性,允许在短时间内存在数据不一致,待系统恢复后,最终会通过后台同步机制确保一致性。

  2. 分布式事务和补偿机制: 订单的操作涉及多个服务和系统模块,例如库存管理、支付、物流等。淘宝通过分布式事务来保证这些操作的最终一致性。例如,系统可能会在库存和订单管理服务之间使用异步消息、队列等技术进行通信,这样在某些情况下如果系统出现故障,仍能通过补偿机制保证事务的最终一致性。补偿机制的核心是在系统恢复后,根据历史记录和操作日志进行回滚或重试,保证订单数据的一致性。

  3. 乐观锁与库存管理: 在淘宝等电商平台中,库存管理是一个非常关键的部分。为了防止库存出现超卖(即多个用户同时购买同一件商品),淘宝使用了乐观锁等技术。在这种情况下,订单创建时,系统会检查库存的状态,并在确认库存足够时创建订单。如果库存不足,系统会通过消息通知用户无法完成购买,避免产生不一致的订单。即使在某些情况下库存状态没有立即同步,最终一致性保证了库存和订单信息最终达成一致。

  4. 订单状态和幂等性设计: 淘宝的订单处理系统中采用了幂等性设计,确保同一订单不会因为重复提交而导致数据不一致。即使在网络波动、请求重试的情况下,系统也能保证每个操作只执行一次,并且结果是唯一的,避免了订单重复或状态错乱的情况。

  5. 异步更新与最终一致性: 例如,当用户下单后,淘宝系统可能会通过异步的方式更新订单状态、发送确认邮件、通知相关部门等。这种异步操作允许系统高效地处理大量请求,而不需要等待所有操作同步完成。这种方式可能导致订单状态在短时间内不同步,但最终通过后台同步或其他一致性机制,确保数据在所有系统间一致。

  6. 库存超卖和订单一致性保障: 淘宝等平台通常会使用 分布式锁消息队列 来防止多次购买同一商品的冲突。例如,当用户支付订单时,系统会先通过分布式锁检查库存,然后再更新库存和订单信息。即使在高并发的情况下,系统也能够通过这些机制保证库存不会超卖,并且最终订单和库存信息会保持一致。

什么是补偿事务?

补偿事务是一种用于保证分布式系统中最终一致性的技术。它并不是传统的回滚操作(如ACID事务中的回滚),而是在出现异常时,通过执行与某个操作相反的操作来恢复系统的一致性。例如,在订单支付失败后,可以通过补偿事务来取消订单或释放库存,从而保证系统数据的一致性。

淘宝如何使用补偿事务?

淘宝等平台采用分布式架构,多个微服务间需要进行协作以完成一个完整的业务流程,例如订单生成、支付、库存扣减、物流派送等。这些业务涉及到多个服务和数据库,因此采用传统的单机事务(ACID)模式并不现实,尤其是在高并发、分布式环境下。

  1. 分布式事务处理: 淘宝通过采用类似 Saga 模式(分布式事务的处理方式)来管理跨服务的业务流程。Saga 模式将一个大事务分解为多个小事务,每个小事务完成后,都有一个补偿事务(rollback action)。如果某个步骤失败,系统会执行对应的补偿操作,确保数据的一致性。

    例如:

    • 用户下单 → 订单服务创建订单
    • 用户支付 → 支付服务确认支付
    • 库存扣减 → 库存服务更新库存 如果支付成功,但库存扣减失败,系统会通过补偿事务取消订单,释放库存,确保系统的数据一致性。
  2. 补偿事务的设计: 在淘宝的系统设计中,补偿事务通常用于以下几种场景:

    • 支付失败:如果用户支付成功,但库存服务由于某些原因无法扣减库存,则通过补偿事务进行回滚,取消订单或者释放库存,避免出现“超卖”问题。
    • 库存问题:如果订单已经创建,但在进行库存扣减时发生了错误,补偿事务会撤销创建的订单,并恢复库存。
    • 订单取消:如果用户选择取消订单,而订单已经进入后续处理流程(如支付、物流),系统会执行补偿事务,恢复订单的状态,防止数据不一致。
  3. 幂等性: 补偿事务的实现需要结合幂等性设计,即相同的操作不会被重复执行导致数据异常。比如,支付服务在用户重复支付请求时,通过幂等性设计保证每次支付请求只会执行一次,避免出现支付失败后再次提交支付造成的问题。

  4. 消息队列与异步处理: 淘宝利用消息队列(如 Kafka)等异步机制处理跨服务的事务,消息传递过程中若某些服务未能正常处理消息,系统会通过补偿事务进行恢复,确保数据最终一致。

补偿事务的优势

  1. 高可用性: 补偿事务允许系统在部分服务失败时,依然保持高可用性,避免因为一个小故障导致整个系统的停滞。

  2. 可靠性: 通过补偿机制,淘宝能够确保在系统发生故障后,能够采取相应的操作恢复系统一致性,避免出现订单重复、库存超卖等问题。

  3. 性能和扩展性: 使用补偿事务与异步消息队列等机制,淘宝能够处理高并发的用户请求,避免因为事务锁的等待导致性能瓶颈。每个子任务的操作可以异步处理,并在失败时通过补偿恢复。

你可能感兴趣的:(分布式,系统架构)