分布式事务几种解决方案

简介: 本文小马参考部分文章,对分布式事务自己做了一下消化和总结整理。

一般来说,事务是必须满足4个条件(ACID)::原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。 参看《MySQL事务隔离级别之理解篇》助于理解。那分布式事务怎么搞呢?

一、两阶段提交(2PC)

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

两阶段分别指准备阶段和提交阶段。

1、准备阶段

协调者询问参与者事务是否执行成功,参与者发回事务执行结果。图表达的不是很直观的话,可以参看这里。

image.png

2、提交阶段

如果事务在每个参与者上都执行成功(测试还没有提交),事务协调者发送通知让参与者提交事务;否则,协调者发送通知让参与者回滚事务。
image.png

3、存在的问题

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

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

数据不一致 在阶段二,如果协调者只发送了部分 Commit 消息,此时网络发生异常,那么只有部分参与者接收到 Commit 消息,也就是说只有部分参与者提交了事务,使得系统数据不一致。(小马觉得这是原子性操作问题)

太过保守 任意一个节点失败就会导致整个事务失败,没有完善的容错机制。(不够这一点貌似也都这样,不是应该就是有一个失败都一起失败吗?)

由此引申出来的3PC,三阶段提交又称3PC,其在两阶段提交的基础上增加了 CanCommit阶段,并引入了 超时机制。一旦事务参与者迟迟没有收到协调者的Commit请求,就会自动进行本地commit,这样相对有效地解决了协调者单点故障的问题。但是性能问题和不一致问题仍然没有根本解决。

二、补偿事务(TCC)

TCC 其实就是采用的补偿机制,其核心思想是:针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作(让我想起tx的ams)。

它分为三个阶段:

Try 阶段主要是对业务系统做检测及资源预留。(先锁资格)

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

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

举个例子,假入 Bob 要向 Smith 转账,思路大概是: 我们有一个本地方法,里面依次调用

首先在 Try 阶段,要先调用远程接口把 Smith 和 Bob 的钱给冻结起来。

在 Confirm 阶段,执行远程调用的转账的操作,转账成功进行解冻。

如果第2步执行成功,那么转账成功,如果第二步执行失败,则调用远程冻结接口对应的解冻方法 (Cancel)。

优点: 跟2PC比起来,实现以及流程相对简单了一些。

缺点: 缺点还是比较明显的,在2,3阶段中都有可能失败--就是锁完资格也不提交也不回滚(数据的一致性比2PC也要差一些),小马认为是打破了原子性操作的原则。小马认为可以对锁加时间,但这个时间必须根据业务来判断,很难准确衡量。TCC属于应用层的一种补偿方式,所以需要程序员在实现的时候多写很多补偿的代码(也可以理解为回滚代码),在一些场景中,一些业务流程可能用TCC不太好定义及处理。

这让我想起了tx的ams,当时处理的是DB增加到指定步数触发发礼包消耗资格。当步数增加成功,礼包发送失败,则需要将新增的步数数据和资格回滚减回去(配置对应的补偿接口),否则会出现步数加到指定步数,礼包没发,之后就没办法再次触发到这个指定步数的礼包了。

曾经在《微服务架构设计模式》一书中被提到使用Saga模式来解决分布式事务,原生分布式框架支持。

Saga(一阶段提交)对于ACID的保证和TCC一样。注意以下对一致性的描述。
image.png

这里提到log可以保证一致性


上面这段啥意思呢?就是TCC有三个动作,try接入需要入侵原来的业务逻辑(锁资源),而saga少了一个try动作(就是我们通常理解的锁资格动作),只需要添加补偿接口即可,等失败了我再调用一个接口补偿一下。一阶段提交,无锁(锁是同步的),性能高,异步补偿动作容易实现(一个独立的补偿接口,假如第三方无法提供try接口也不怕),适用于此类场景。

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT(Java 2PC)、TCC、SAGA(对于ACID的保证和TCC一样) 和 XA (JAVA 支持XA 事务的数据库)事务模式,为用户打造一站式的分布式解决方案。(所以没有语言限制的是TCC、SAGA)。

Saga模式是SEATA提供的长事务解决方案,在Saga模式中,业务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务都由业务开发实现。

image.png

三、本地消息表(异步确保)

本地消息表与业务数据表处于同一个数据库中,这样就能利用本地事务来保证在对这两个表的操作满足事务特性(ACID),并且使用了消息队列来保证最终一致性。

这句话啥意思呢?你不是有DB吗?DB一般不是都具备事务机制吗,比如MySQL事务。那我能不能利用它把我的本地的A事务先执行完,写两个表A业务执行表,B本地消息表,本地消息表代表了这个和A业务需要一起执行的B业务。然后B本地消息表把这个请求放入消息队列,B业务去消费这个队列把剩下的B业务执行完毕。以此来异步达到事务的最终一致性。只要消费队列消息可靠性(一般kafka可靠性好)有保证不丢失,最终肯定会达到一致性。
image.png

1、在分布式事务操作的一方完成写业务数据的操作之后向本地消息表发送一个消息,本地事务能保证这个消息一定会被写入本地消息表中。

2、之后将本地消息表中的消息转发到 Kafka 等消息队列中,如果转发成功则将消息从本地消息表中删除,否则继续重新转发。

3、在分布式事务操作的另一方从消息队列中读取一个消息,并执行消息中的操作。

优点: 一种非常经典的实现,避免了分布式事务(用本地DB事务 + 异步来转换),实现了最终一致性。(小马觉得这个思想非常秒,移花接木的感觉)

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

四、MQ 事务消息

这一块涉及借助MQ的实现,小马就知识涉猎了,直接借用网络上的文章来说明,在此感谢原作者分享,原文。

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

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

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

上面这段什么意思呢?我们看图来分析。

1、消息发送者发送消息到消息队列。第一阶段Prepared消息,会拿到消息的地址。

2、第二阶段执行本地事务,并发送确认消息到刚刚拿到地址的消息队列,并修改状态。如果确认消息发送失败了RocketMQ会定期扫描消息集群中的事务消息,如果发现了Prepared消息,它会向消息发送者确认。所以生产方(消息发送者)需要实现一个check接口,RocketMQ会根据发送端设置的策略来决定是回滚还是继续发送确认消息。这样就保证了消息发送(事务交给消息队列控制,就不需要本地消息表了)与本地事务同时成功或同时失败。

3、4、这个步骤就是和本地消息表后面一样的道理了,异步来执行剩下的事务逻辑,达到最终一致性。

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

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

小马的疑问是,如果这个事务链条很长,处理起来是不是会相当复杂,而且异步造成的延迟是不是也是应该考虑的问题(必须先锁住所有资格)?

总结

分布式事务本身是一个技术难题,和微服务一样,也没有所谓的银弹吧,根据不同的场景和实际情况选择吧。这句话你信?反正小马也非深究亲践,待小马大杀四方一下回来再把酒话桑麻,分享补充,总结一下。

相关实践学习
快速体验阿里云云消息队列RocketMQ版
本实验将带您快速体验使用云消息队列RocketMQ版Serverless系列实例进行获取接入点、创建Topic、创建订阅组、收发消息、查看消息轨迹和仪表盘。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
存储 SQL 微服务
常用的分布式事务解决方案(三)
常用的分布式事务解决方案(三)
|
关系型数据库 MySQL
常见分布式事务的解决方案(一)
常见分布式事务的解决方案(一)
|
负载均衡 NoSQL 算法
Redisson分布式锁数据一致性解决方案
通过以上的设计和实现, Redisson能够有效地解决分布式环境下数据一致性问题。但是, 任何技术都不可能万无一失, 在使用过程中还需要根据实际业务需求进行逻辑屏障的设计和错误处理机制的建立。
730 48
|
缓存 NoSQL PHP
Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出
本文深入探讨了Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出。文章还介绍了Redis在页面缓存、数据缓存和会话缓存等应用场景中的使用,并强调了缓存数据一致性、过期时间设置、容量控制和安全问题的重要性。
463 5
|
存储 NoSQL Java
一天五道Java面试题----第十一天(分布式架构下,Session共享有什么方案--------->分布式事务解决方案)
这篇文章是关于Java面试中的分布式架构问题的笔记,包括分布式架构下的Session共享方案、RPC和RMI的理解、分布式ID生成方案、分布式锁解决方案以及分布式事务解决方案。
一天五道Java面试题----第十一天(分布式架构下,Session共享有什么方案--------->分布式事务解决方案)
|
消息中间件 中间件 关系型数据库
常用的分布式事务解决方案(四)
常用的分布式事务解决方案(四)
常用的分布式事务解决方案(二)
常用的分布式事务解决方案(二)
|
机器学习/深度学习 分布式计算 Cloud Native
云原生架构下的高性能计算解决方案:利用分布式计算资源加速机器学习训练
【8月更文第19天】随着大数据和人工智能技术的发展,机器学习模型的训练数据量和复杂度都在迅速增长。传统的单机训练方式已经无法满足日益增长的计算需求。云原生架构为高性能计算提供了新的可能性,通过利用分布式计算资源,可以在短时间内完成大规模数据集的训练任务。本文将探讨如何在云原生环境下搭建高性能计算平台,并展示如何使用 PyTorch 和 TensorFlow 这样的流行框架进行分布式训练。
612 2
|
存储 监控 数据可视化
性能监控之JMeter分布式压测轻量日志解决方案
【8月更文挑战第11天】性能监控之JMeter分布式压测轻量日志解决方案
660 0
性能监控之JMeter分布式压测轻量日志解决方案
|
关系型数据库 分布式数据库 数据库
PolarDB,阿里云的开源分布式数据库,与微服务相结合,提供灵活扩展和高效管理解决方案。
【7月更文挑战第3天】PolarDB,阿里云的开源分布式数据库,与微服务相结合,提供灵活扩展和高效管理解决方案。通过数据分片和水平扩展支持微服务弹性,保证高可用性,且兼容MySQL协议,简化集成。示例展示了如何使用Spring Boot配置PolarDB,实现服务动态扩展。PolarDB缓解了微服务数据库挑战,加速了开发部署,为云原生应用奠定基础。
806 3

热门文章

最新文章