浅谈分布式事务解决方案

2023年04月14日 11:54   广州金融科技
采用微服务架构进行建设的项目,微服务、数据库等组成部分分别位于不同的服务器节点上,每个数据库都有独立的本地事务,事务之间相互隔离,为解决这种情况下的事务问题,多种分布式事务解决方案诞生了。

综述:

采用微服务架构进行建设的项目,微服务、数据库等组成部分分别位于不同的服务器节点上,每个数据库都有独立的本地事务,事务之间相互隔离,为解决这种情况下的事务问题,多种分布式事务解决方案诞生了。

一、 一致性理论分布式

事务的目的是保障分库数据一致性,而跨库事务会遇到各种不可控制的问题,如个别节点永久性宕机,像单机事务一样的ACID(数据库事务正确执行的四要素缩写)是无法奢望的。另外,业界著名的CAP理论也告诉我们,对分布式系统,需要将数据一致性和系统可用性、分区容忍性放在天平上一起考虑。

两阶段提交协议(简称“2PC”)是实现分布式事务较为经典的方案,但2PC 的可扩展性很差,在分布式架构下应用代价较大,EBay 架构师Dan Pritchett提出了BASE理论,用于解决大规模分布式系统下的数据一致性问题。BASE理论告诉我们:可以通过放弃系统在每个时刻的强一致性来换取系统的可扩展性。

1.CAP理论

在分布式系统中,一致性(Consistency)、可用性(Availability)和分区容忍性(Partition Tolerance)3 个要素最多只能同时满足两个,不可兼得。其中,分区容忍性又是不可或缺的。

  • 一致性:分布式环境下多个节点的数据是否强一致。

  • 可用性:分布式服务能一直保证可用状态。当用户发出一个请求后,服务能在有限时间内返回结果。

  • 分区容忍性:特指对网络分区的容忍性。举例:Cassandra、Dynamo等,默认优先选择AP,弱化C;HBase、MongoDB等,默认优先选择CP,弱化A。

2.BASE理论

  • 基本可用(Basically Available):指分布式系统在出现故障时,允许损失部分的可用性来保证核心可用。

  • 软状态(Soft State):指允许分布式系统存在中间状态,该中间状态不会影响到系统的整体可用性。

  • 最终一致性(Eventual Consistency):指分布式系统中的所有副本数据经过一定时间后,最终能够达到一致的状态。

二、 一致性模型


数据的一致性模型可以分成以下 3 类:

强一致性:数据更新成功后,任意时刻所有副本中的数据都是一致的,一般采用同步的方式实现。

弱一致性:数据更新成功后,系统不承诺立即可以读到最新写入的值,也不承诺具体多久之后可以读到。

最终一致性:弱一致性的一种形式,数据更新成功后,系统不承诺立即可以返回最新写入的值,但是保证最终会返回上一次更新操作的值。

三、 分布式事务解决方案

1.两阶段提交(2PC)

两阶段提交(Two-phase Commit,2PC),通过引入协调者(Coordinator)来协调参与者的行为,并最终决定这些参与者是否要真正执行事务。

1.1 运行过程

1.1.1 准备阶段

协调者询问参与者事务是否执行成功,参与者发回事务执行结果。

1.1.2 提交阶段

如果事务在每个参与者上都执行成功,事务协调者发送通知让参与者提交事务;否则,协调者发送通知让参与者回滚事务。

需要注意的是,在准备阶段,参与者执行了事务,但是还未提交。只有在提交阶段接收到协调者发来的通知后,才进行提交或者回滚。

1.2 存在的问题

1.2.1 同步阻塞 所有事务参与者在等待其它参与者响应的时候都处于同步阻塞状态,无法进行其它操作。

1.2.2 单点问题 协调者在 2PC 中起到非常大的作用,发生故障将会造成很大影响。特别是在阶段二发生故障,所有参与者会一直等待状态,无法完成其它操作。

1.2.3 数据不一致 在阶段二,如果协调者只发送了部分 Commit 消息,此时网络发生异常,那么只有部分参与者接收到 Commit 消息,也就是说只有部分参与者提交了事务,使得系统数据不一致。

1.2.4 太过保守 任意一个节点失败就会导致整个事务失败,没有完善的容错机制。

2.补偿事务(TCC)

TCC其实就是采用的补偿机制,其核心思想是:针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作。它分为三个阶段:

  • Try阶段主要是对业务系统做检测及资源预留

  • Confirm阶段主要是对业务系统做确认提交,Try阶段执行成功并开始执行 Confirm阶段时,默认 Confirm阶段是不会出错的。即:只要Try成功,Confirm一定成功。

  • Cancel阶段主要是在业务执行错误,需要回滚的状态下执行的业务取消,预留资源释放。

举个例子,假如Bob要向Smith转账,思路大概是:我们有一个本地方法,里面依次调用。首先在Try阶段,要先调用远程接口把 Smith和 Bob的钱给冻结起来。在 Confirm阶段,执行远程调用的转账的操作,转账成功进行解冻。如果第Confirm步执行成功,那么转账成功,如果第二步执行失败,则调用远程冻结接口对应的解冻方法 (Cancel)。

优点:跟2PC比起来,实现以及流程相对简单了一些,但数据的一致性比2PC也要差一些。

缺点:缺点还是比较明显的,在2,3步中都有可能失败。TCC属于应用层的一种补偿方式,所以需要程序员在实现的时候多写很多补偿的代码,在一些场景中,一些业务流程可能用TCC不太好定义及处理。

3.MQ消息事务

有一些第三方的MQ是支持事务消息的,比如RocketMQ,他们支持事务消息的方式也是类似于采用的二阶段提交,但是市面上一些主流的MQ都是不支持事务消息的,比如 abbitMQ和Kafka都不支持。

以阿里的RocketMQ中间件为例,其思路大致为:

第一阶段Prepared消息,会拿到消息的地址。第二阶段执行本地事务,第三阶段通过第一阶段拿到的地址去访问消息,并修改状态。

也就是说在业务方法内要想消息队列提交两次请求,一次发送消息和一次确认消息。如果确认消息发送失败了RocketMQ会定期扫描消息集群中的事务消息,这时候发现了Prepared消息,它会向消息发送者确认,所以生产方需要实现一个check接口,RocketMQ会根据发送端设置的策略来决定是回滚还是继续发送确认消息。这样就保证了消息发送与本地事务同时成功或同时失败。

优点: 实现了最终一致性,不需要依赖本地数据库事务。

缺点: 实现难度大,主流MQ不支持,RocketMQ事务消息部分代码也未开源。

四、 总结

每个分布式事务解决方案都有着自身的优点与缺点,分布式事务本身是一个技术难题,没有一种完美的解决方案是可以应对所有场景的,具体还是要根据业务场景去选择合适的解决方案。

本文内容为原创,转载请注明出处!

关注我们

站长统计