分布式事务

如果本文有错,希望在下面的留言区指正。

在之前的一篇文章中,写了一篇 Spring 事务管理

本地事务管理主要考虑的是单台服务器上面的事务回滚。那么,如果在分布式服务之间如何管理事务呢?

如上图所示的分布式调用,客户端 client 调用服务A,而服务A 除了本身的对数据库的修改,还需要调用服务B和服务C。如果在调用服务B成功后在调用服务C,但是这时候服务C出错了,这时候如何解决事务的回滚?

CAP

CAP 理论是分布式系统的一个基础理论,描述任何一个分布式系统最多只能满足下面三种特性中的两个:

  • 一致性(Consistency):对某个指定的客户端来说,读操作保证能够返回最新的写操作结果。
  • 可用性(Availability):非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)。
  • 分区容忍性(Partition tolerance):当出现网络分区后,系统能够继续“履行职责”。

CAP 的选择

虽然 CAP 理论定义是三个要素中只能取两个,但放到分布式环境下来思考,我们会发现必须选择 P(分区容忍)要素,因为网络本身无法做到 100% 可靠,有可能出故障,所以分区是一个必然的现象。如果我们选择了 CA 而放弃了 P,那么当发生分区现象时,为了保证 C,系统需要禁止写入,当有写入请求时,系统返回 error(例如,当前系统不允许写入),这又和 A 冲突了,因为 A 要求返回 no error 和 no timeout。因此,分布式系统理论上不可能选择 CA 架构,只能选择 CP 或者 AP 架构。

BASE

BASE 思想解决了 CAP 提出的分布式系统的一致性和可用性不可兼容的问题。BASE 思想与 ACID 原理完全不同,它满足于 CAP 原理,通过牺牲强一致性获取可用性,一般应用于服务化系统的应用层或者大数据处理系统中,通过达到最终一致性来尽量满足业务的绝大多数需求。

BASE 模型包含以下三个元素:

  • BA:Basically Available,基本可用
  • S:Soft state,软状态,状态可以在一段时间内不同步
  • E:Eventually consistent,最终一致性,在一定的时间窗口内,最终数据达到一致性即可。

目前的分布式事务的解决方案

两阶段提交 2PC

2PC 又称 XA Transactions,XA 是一个两阶段提交协议,该协议分为以下两个阶段:

  • 第一阶段:事务协调器要求每个涉及到事务的数据库预提交(precommit)此操作,并反映是否可以提交.
  • 第二阶段:事务协调器要求每个数据库提交数据。

补偿事务 TCC

TCC 其实就是采用的补偿机制,其核心思想是:针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作。TCC模型是把锁的粒度完全交给业务处理。它分为三个阶段:

  • Try 阶段主要是对业务系统做检测及资源预留
  • Confirm 阶段主要是对业务系统做确认提交,Try阶段执行成功并开始执行 Confirm阶段时,默认 Confirm阶段是不会出错的。即:只要Try成功,Confirm一定成功。
  • Cancel 阶段主要是在业务执行错误,需要回滚的状态下执行的业务取消,预留资源释放。

基于 TCC 源码

本地消息表

本地消息表这种实现方式应该是业界使用最多的,其核心思想是将分布式事务拆分成本地事务进行处理,这种思路是来源于ebay。我们可以从下面的流程图中看出其中的一些细节:

消息生产方,需要额外建一个消息表,并记录消息发送状态。消息表和业务数据要在一个事务里提交,也就是说他们要在一个数据库里面。然后消息会经过MQ发送到消息的消费方。如果消息发送失败,会进行重试发送。

消息消费方,需要处理这个消息,并完成自己的业务逻辑。此时如果本地事务处理成功,表明已经处理成功了,如果处理失败,那么就会重试执行。如果是业务上面的失败,可以给生产方发送一个业务补偿消息,通知生产方进行回滚等操作。

生产方和消费方定时扫描本地消息表,把还没处理完成的消息或者失败的消息再发送一遍。如果有靠谱的自动对账补账逻辑,这种方案还是非常实用的。

这种方案遵循BASE理论,采用的是最终一致性,笔者认为是这几种方案里面比较适合实际业务场景的,即不会出现像2PC那样复杂的实现(当调用链很长的时候,2PC的可用性是非常低的),也不会像TCC那样可能出现确认或者回滚不了的情况。

优点: 一种非常经典的实现,避免了分布式事务,实现了最终一致性。在 .NET 中 有现成的解决方案。

缺点: 消息表会耦合到业务系统中,如果没有封装好的解决方案,会有很多杂活需要处理。

MQ 事务

有一些第三方的MQ是支持事务消息的,比如RocketMQ,但是市面上一些主流的MQ都是不支持事务消息的,比如 RabbitMQ 和 Kafka 都不支持。

阿里的 GTS

阿里的 GTS 没有开源,需要购买它的产品,同时需要配套的分布式数据库。

参考

博主 wechat
钟意作者
客官,赏一杯coffee嘛~~~~
0%