分布式事务有哪些解决方案?

41 阅读9分钟

在分布式系统中,分布式事务是一个关键且具有挑战性的问题。当业务操作涉及多个不同的服务或数据源时,如何确保这些操作要么全部成功执行,要么全部不执行,以保持数据的一致性呢?下面我们来探讨一下分布式事务的几种常见解决方案。

一、分布式事务的定义

分布式事务关注的是分布式场景下如何处理事务。它是指事务的参与者、支持事务操作的服务器、存储等资源分别位于分布式系统的不同节点之上。简单来说,分布式事务就是一个业务操作由多个细分操作完成,而这些细分操作又分布在不同的服务器上。事务的要求是这些操作要么全部成功执行,要么全部不执行。

二、分布式事务产生的原因

分布式事务是随着系统拆分而出现的。前面我们提到,分布式系统解决了海量数据服务对扩展性的要求,但也增加了架构上的复杂性,分布式事务就是这一复杂性的典型体现。

在实际开发中,分布式事务产生的原因主要源于存储和服务的拆分。

1. 存储层拆分

存储层拆分最典型的就是数据库分库分表。一般来说,当单表容量达到千万级时,就要考虑数据库拆分,从单一数据库变成多个分库和多个分表。在业务中如果需要进行跨库或者跨表更新,同时要保证数据的一致性,就会产生分布式事务问题。

2. 服务层拆分

服务层拆分也就是业务的服务化。系统架构从集中式演进到分布式,业务功能之间越来越解耦合。

比如电商网站系统,业务初期可能是一个单体工程支撑整套服务,但随着系统规模进一步变大,参考康威定律,大多数公司都会将核心业务抽取出来,作为独立的服务。商品、订单、库存、账号信息都提供了各自领域的服务,业务逻辑的执行散落在不同的服务器上。

用户在某网站上进行下单操作时,会同时依赖订单服务、库存服务、支付扣款服务。如果这几个操作中有一个失败,那下单操作也就无法完成,这就需要分布式事务来保证。

三、两阶段提交(2PC)

  1. 定义与原理

    • 两阶段提交(2PC,Two-phase Commit Protocol)是一种经典的强一致性、中心化的原子提交协议。它将事务的提交过程分为两个阶段:准备阶段和提交阶段。
    • 在准备阶段,事务协调者向所有参与者发送准备请求,参与者执行事务操作但不提交,然后回复是否准备好提交。如果所有参与者都回复准备好,那么进入提交阶段;否则,事务协调者向所有参与者发送回滚请求。
    • 在提交阶段,事务协调者根据准备阶段的结果决定是提交还是回滚事务。如果所有参与者都准备好,协调者发送提交请求,参与者提交事务;否则,发送回滚请求,参与者回滚事务。
  2. 优点

    • 强一致性保证:确保事务要么全部成功,要么全部失败,不会出现数据不一致的情况。
  3. 缺点

    • 性能问题:由于需要在两个阶段进行通信和协调,会导致较长的事务执行时间,降低系统的性能。
    • 单点故障:事务协调者是关键节点,如果协调者出现故障,整个事务将无法完成。

四、三阶段提交(3PC)

  1. 定义与原理

    • 三阶段提交协议(3PC,Three-phase_commit_protocol)是在 2PC 的基础上扩展而来,主要是为了解决 2PC 的阻塞问题。它将提交过程分为三个阶段:CanCommit、PreCommit 和 DoCommit。
    • 在 CanCommit 阶段,事务协调者询问参与者是否可以执行事务,参与者回复是否可以。如果所有参与者都回复可以,进入 PreCommit 阶段;否则,事务中断。
    • 在 PreCommit 阶段,协调者向参与者发送预提交请求,参与者执行事务操作并记录日志,但不提交。如果所有参与者都回复成功,进入 DoCommit 阶段;否则,协调者向所有参与者发送中断请求。
    • 在 DoCommit 阶段,如果在 PreCommit 阶段所有参与者都回复成功,协调者发送提交请求,参与者提交事务;否则,发送回滚请求,参与者回滚事务。
  2. 优点

    • 引入超时机制:减少了 2PC 中因参与者等待协调者而导致的阻塞时间,提高了系统的可用性。
  3. 缺点

    • 仍然存在单点故障问题:虽然减少了阻塞时间,但事务协调者仍然是关键节点,一旦出现故障,事务可能无法完成。

五、TCC(Try-Confirm-Cancel)

  1. 定义与原理

    • TCC 是一个分布式事务的处理模型,将事务过程拆分为 Try、Confirm、Cancel 三个步骤。
    • Try 阶段:尝试执行事务的业务操作,预留资源,但不提交事务。
    • Confirm 阶段:确认执行事务,如果 Try 阶段成功,则提交事务;否则,不执行 Confirm 操作。
    • Cancel 阶段:如果 Try 阶段失败或者出现异常,执行 Cancel 操作,释放预留的资源。
  2. 优点

    • 高可用性:由于每个阶段都是独立的,可以在出现故障时进行重试或回滚,提高了系统的可用性。
    • 灵活性:可以根据业务需求自定义 Try、Confirm、Cancel 三个阶段的具体操作,适应不同的业务场景。
  3. 缺点

    • 开发复杂度高:需要开发者实现 Try、Confirm、Cancel 三个阶段的逻辑,增加了开发的难度和工作量。

六、基于消息队列的最终一致性

  1. 定义与原理

    • 基于消息队列的最终一致性是一种异步事务机制。通过消息队列将事务操作异步化,确保在事务的各个阶段都能将消息发送到消息队列中,然后由消费者异步地处理这些消息,最终达到数据的一致性。
  2. 实现方式

    • 本地消息表:消息生产方在本地建立一个事务消息表,记录事务的状态和消息内容。在事务成功提交后,将消息发送到消息队列中。消息消费方从消息队列中获取消息,进行业务处理,并更新本地消息表的状态。如果出现异常,可以通过定时任务扫描本地消息表,重新处理未完成的事务。
    • 第三方可靠消息队列:使用可靠的消息中间件,如 RabbitMQ、Kafka 等,确保消息的可靠传输和消费。消息生产方将事务操作和消息发送封装在一个本地事务中,确保事务操作和消息发送要么都成功,要么都失败。消息消费方从消息队列中获取消息,进行业务处理,并向消息中间件发送确认消息。如果消息中间件在一定时间内没有收到确认消息,会重新发送消息,直到消息被成功处理。
  3. 优点

    • 性能高:异步处理事务,减少了事务的执行时间,提高了系统的性能。
    • 解耦性好:通过消息队列将事务操作解耦,各个服务之间的依赖关系降低,提高了系统的可扩展性。
  4. 缺点

    • 最终一致性:不能保证事务的强一致性,可能会出现短暂的数据不一致情况,需要在业务上能够接受最终一致性。

七、不要求最终一致性的柔性事务

  1. 定义与原理

    • 柔性事务也称为尽最大努力通知,适合可以接受部分不一致的业务场景。在这种事务模型中,事务的执行不保证强一致性,而是通过尽最大努力去通知各个参与者执行事务操作,但不保证所有参与者都能成功执行。
  2. 实现方式

    • 消息通知:事务发起方在完成事务操作后,向各个参与者发送消息通知。参与者接收到通知后,尝试执行事务操作,但不保证一定成功。如果出现失败,可以进行重试或者记录日志,以便后续处理。
  3. 优点

    • 简单高效:不需要复杂的事务协调机制,实现简单,性能高。
  4. 缺点

    • 数据不一致风险高:由于不保证强一致性,可能会出现数据不一致的情况,需要在业务上进行特殊处理。

八、总结

分布式事务是分布式系统中的一个复杂问题,不同的解决方案各有优缺点。在实际应用中,需要根据业务需求、系统架构和性能要求等因素选择合适的分布式事务解决方案。如果对数据一致性要求非常高,可以选择 2PC 或 3PC;如果希望提高系统的可用性和性能,可以选择 TCC 或基于消息队列的最终一致性;如果业务可以接受部分不一致,可以选择柔性事务。无论选择哪种方案,都需要在设计和实现过程中充分考虑事务的隔离性、原子性、一致性和持久性,以确保系统的稳定性和可靠性。

文章(专栏)将持续更新,欢迎关注公众号:服务端技术精选。欢迎点赞、关注、转发

个人小工具程序上线啦,通过公众号(服务端技术精选)菜单【个人工具】即可体验,欢迎大家体验后提出优化意见