您当前的位置:首页 > 电脑百科 > 程序开发 > 架构

浅谈分布式事务及解决方案

时间:2023-10-17 12:34:33  来源:  作者:京东云开发者

1 背景

 

在讲述分布式事务的概念之前,我们先来回顾下事务相关的一些概念。

1.1 事务的基本概念

就是一个程序执行单元,里面的操作要么全部执行成功,要么全部执行失败,不允许只成功一半另外一半执行失败的事情发生。例如一段事务代码做了两次数据库更新操作,那么这两次数据库操作要么全部执行成功,要么全部回滚。

1.2 事务的基本特性

我们知道事务有 4 个非常重要的特性,即我们常说的(ACID)。

  • Atomicity(原子性):一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
  • Consistency(一致性):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
  • Isolation(隔离性):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
  • Durability(持久性):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失

2 分布式事务

其实分布式事务从实质上看与数据库事务的概念是一致的,既然是事务也就需要满足事务的基本特性(ACID),只是分布式事务相对于本地事务而言其表现形式有很大的不同。

本地事务的时代,如果需要同时操作数据库的多条记录,而这些操作可以放到一个事务中,那么我们可以通过数据库提供的事务机制就可以实现。

而随着微服务架构的推进,原本一个本地逻辑执行单元,被拆分到了多个独立的微服务中,这些微服务又分别操作了不同的数据库和表。

比如下个指派个体的运输任务,下运输任务的同时要生成需求、计划、任务,还要去调用询价服务,投保服务,那么,一旦产生任何一个服务异常,都会产生事务性的问题。虽然对于我们现有逻辑来说,可以由运营作废,但未来自动化之后呢?

分布式事务是为了解决微服务架构(形式都是分布式系统)中不同节点之间的数据一致性问题。这个一致性问题本质上解决的也是传统事务需要解决的问题,即一个请求在多个微服务调用链中,所有服务的数据处理要么全部成功,要么全部回滚。当然分布式事务问题的形式可能与传统事务会有比较大的差异,但是问题本质是一致的,都是要求解决数据的一致性问题。

而分布式事务的实现方式有很多种,最具有代表性的是由 Oracle Tuxedo 系统提出的 XA 分布式事务协议。XA 协议包括两阶段提交(2PC)和三阶段提交(3PC)两种实现,接下来我们分别来介绍下这两种实现方式的原理。

3 两阶段提交(2PC)

两阶段提交又称 2PC(two-phase commit protocol),2PC 是一个非常经典的强一致、中心化的原子提交协议。这里所说的中心化是指协议中有两个角色:一个是分布式事务协调者(coordinator)和 N 个参与者(participant)。

3.1 2PC 运行原理

两阶段提交,顾名思义就是要进行两个阶段的提交:第一阶段,准备阶段(投票阶段);第二阶段,提交阶段(执行阶段)。

3.1.1 准备阶段(Prepare phase)

浅谈分布式事务及解决方案

  1. 分布式事务的发起方,向分布式事务协调者(Coordinator,也可以叫事务管理 TransactionManager)发送请求,
  2. Coordinator 分别向参与者(Participant)A、参与者(Participant)B 分别发送事务预处理请求,称之为 Prepare,有些资料也叫”Vote Request”。
  3. 此时这些参与者节点一般来说就会打开本地数据库事务,然后开始执行数据库本地事务,每个数据库参与者在本地执行事务并写本地的 Undo/Redo 日志(Undo 日志是记录修改前的数据,用于数据库回滚,Redo 日志是记录修改后的数据,用于提交事务后写入数据文件),但在执行完成后并不会立马提交数据库本地事务,而是先向 Coordinator 进行 “Vote Commit” 的反馈,告知处理结果。
  4. 如果所有的参与者都向协调者做了 “Vote Commit” 的反馈的话,那么流程进入第二个阶段。

3.1.2 提交阶段(commit phase)

浅谈分布式事务及解决方案

1)如果所有参与者均反馈的是成功,协调者就会向所有参与者发送 “全局提交确认通知(global_commit)”,参与者 Participant 就会完成自身本地数据库事务的提交,并将提交结果回复 “ack” 消息给协调者 Coordinator,然后协调者 Coordinator 就会向调用方返回分布式事务处理完成的结果。如果有任何一个参与者返回失败,则回滚事务。

浅谈分布式事务及解决方案

2)如果参与者向协调者反馈 “Vote_Abort” 消息,即返回了失败的消息。此时分布式事务协调者 Coordinator 就会向所有的参与者 Participant 发起事务回滚的消息(“global_rollback”),此时各个参与者就会回滚本地事务,释放资源,并且向协调者发送 “ack” 确认消息,协调者就会向调用方返回分布式事务处理失败的结果。

浅谈分布式事务及解决方案

以上就是两阶段提交的基本过程了,那么按照这个两阶段提交协议,分布式系统的数据一致性问题就能解决么?

3.2 2PC 存在的问题

其实,2PC 只是通过增加了事务协调者(Coordinator)的角色来通过 2 个阶段的处理流程来解决分布式系统中一个事务需要跨多个服务的数据一致性问题。

以下几点是 XA - 两阶段提交协议中会遇到的一些问题:

  • 性能问题:2PC 中的所有的参与者节点都为事务阻塞型,当某一个参与者节点出现通信超时,其余参与者都会被动阻塞占用资源不能释放。
  • 协调者单点故障问题:由于严重的依赖协调者,一旦协调者发生故障,而此时参与者还都处于锁定资源的状态,无法完成事务 commit 操作。虽然协调者出现故障后,会重新选举一个协调者,可无法解决因前一个协调者宕机导致的参与者处于阻塞状态的问题。
  • 网络闪断导致脑裂:第二阶段中协调者向参与者发送 commit 命令之后,一旦此时发生网络抖动,导致一部分参与者接收到了 commit 请求并执行,可其他未接到 commit 请求的参与者无法执行事务提交。进而导致整个分布式系统出现了数据不一致。

4 三阶段提交(3PC)

三阶段提交又称 3PC,在 2PC 的基础上增加了 CanCommit 阶段,并引入了超时机制。一旦事务参与者迟迟没有收到协调者的 Commit 请求,就会自动进行本地 commit,这样相对有效地解决了协调者单点故障的问题。

4.1 3PC 运行原理

4.1.1 CanCommit 阶段

  1. 协调者向参与者发出 CanCommit ,进行事务询问操作,所有参与者都反馈 yes 后,才能进入下一个阶段。(这一个阶段时不锁表,不像 2pc 第一个阶段就开始锁表,3pc 的阶段一是为了先排除个别参与者不具备提交事务能力的前提下,而避免锁表。)简单来说就是检查下自身状态的健康性。
  2. 有任何一个参与者反馈的结果是 No,整个分布式事务就会中断,协调者就会向所有的参与者发送 “abort” 请求。

4.1.2 PreCommit 阶段

  1. 在阶段一中,如果所有的参与者都返回 Yes 的话,那么就会进入 PreCommit 阶段进行事务预提交。此时分布式事务协调者会向所有的参与者发送 PreCommit 请求,参与者收到后开始执行事务操作,并将 Undo 和 Redo 信息记录到事务日志中。参与者执行完事务操作后(此时属于未提交事务的状态),就会向协调者反馈 “Ack” 表示已经准备好提交,并等待协调者的下一步指令。
  2. 有任何一个参与者反馈的结果是 No,或协调者在等待参与者节点反馈的过程中超时(2PC 中只有协调者可以超时,参与者没有超时机制)。整个分布式事务就会中断,协调者就会向所有的参与者发送 “abort” 请求。

4.1.3 DoCommit 阶段

  1. 在阶段二中如果所有的参与者都可以进行 PreCommit 提交,那么协调者就会从 “预提交状态”->“提交状态”。然后向所有的参与者发送”doCommit” 请求,参与者在收到提交请求后,执行事务提交操作,并向协调者反馈 “Ack” 消息,协调者收到所有参与者的 Ack 消息后完成事务。
  2. 同样,如果有一个参与者节点未完成 PreCommit 的反馈或者反馈超时,那么协调者都会向所有的参与者节点发送 abort 请求,从而中断事务。

浅谈分布式事务及解决方案

相比较 2PC 而言,3PC 对于协调者(Coordinator)和参与者(Participant)都设置了超时时间,解决了参与者在长时间无法与协调者节点通讯(协调者挂掉了)的情况下,无法释放资源的问题,因为参与者自身拥有超时机制会在超时后,自动进行本地 commit 从而进行释放资源。而这种机制也侧面降低了整个事务的阻塞时间和范围。

另外,通过 CanCommit、PreCommit、DoCommit 三个阶段的设计,相较于 2PC 而言,多设置了一个缓冲阶段保证了在最后提交阶段之前各参与节点的状态是一致的。

3PC 的缺点:

3PC 在去除阻塞的同时也引入了新的问题,那就是参与者接收到 precommit 消息后,如果出现网络分区,此时协调者所在的节点和参与者无法进行正常的网络通信,在这种情况下,该参与者依然会进行事务的提交,这必然出现数据的不一致性。

5 补偿事务(TCC)

TCC 与 2PC、3PC 一样,只是分布式事务的一种实现方案。

5.1 TCC 原理:

TCC(Try-Confirm-Cancel)又称补偿事务。其核心思想是:” 针对每个操作都要注册一个与其对应的确认和补偿(撤销操作)”。它分为三个操作:

  • Try 阶段:主要是对业务系统做检测及资源预留,比如说冻结库存。
  • Confirm 阶段:确认执行业务操作。
  • Cancel 阶段:取消执行业务操作。

TCC 事务的处理流程与 2PC 两阶段提交类似,不过 2PC 通常都是在跨库的 DB 层面,而 TCC 本质上就是一个应用层面的 2PC,需要通过业务逻辑来实现。这种分布式事务的实现方式的优势在于,可以让应用自己定义数据库操作的粒度,使得降低锁冲突、提高吞吐量成为可能。

而不足之处则在于对应用的侵入性非常强,业务逻辑的每个分支都需要实现 try、confirm、cancel 三个操作。此外,其实现难度也比较大,需要按照网络状态、系统故障等不同的失败原因实现不同的回滚策略。为了满足一致性的要求,confirm 和 cancel 接口还必须实现幂等。

TCC 的具体原理图如下:

浅谈分布式事务及解决方案

5.2 注意事项:

1. 业务操作分两阶段完成:

接入 TCC 前,业务操作只需要一步就能完成,但是在接入 TCC 之后,需要考虑如何将其分成 2 阶段完成,把资源的检查和预留放在一阶段的 Try 操作中进行,把真正的业务操作的执行放在二阶段的 Confirm 操作中进行;

TCC 服务要保证第一阶段 Try 操作成功之后,二阶段 Confirm 操作一定能成功;

浅谈分布式事务及解决方案

2. 允许空回滚;

事务协调器在调用 TCC 服务的一阶段 Try 操作时,可能会出现因为丢包而导致的网络超时,此时事务协调器会触发二阶段回滚,调用 TCC 服务的 Cancel 操作;

TCC 服务在未收到 Try 请求的情况下收到 Cancel 请求,这种场景被称为空回滚;TCC 服务在实现时应当允许空回滚的执行;

浅谈分布式事务及解决方案

3. 防悬挂控制;

事务协调器在调用 TCC 服务的一阶段 Try 操作时,可能会出现因网络拥堵而导致的超时,此时事务协调器会触发二阶段回滚,调用 TCC 服务的 Cancel 操作;在此之后,拥堵在网络上的一阶段 Try 数据包被 TCC 服务收到,出现了二阶段 Cancel 请求比一阶段 Try 请求先执行的情况;

用户在实现 TCC 服务时,应当允许空回滚,但是要拒绝执行空回滚之后到来的一阶段 Try 请求;

浅谈分布式事务及解决方案

4. 幂等控制:

无论是网络数据包重传,还是异常事务的补偿执行,都会导致 TCC 服务的 Try、Confirm 或者 Cancel 操作被重复执行;用户在实现 TCC 服务时,需要考虑幂等控制,即 Try、Confirm、Cancel 执行次和执行多次的业务结果是一样的;

5. 业务数据可见性控制;

TCC 服务的一阶段 Try 操作会做资源的预留,在二阶段操作执行之前,如果其他事务需要读取被预留的资源数据,那么处于中间状态的业务数据该如何向用户展示,需要业务在实现时考虑清楚;通常的设计原则是 “宁可不展示、少展示,也不多展示、错展示”;

6. 业务数据并发访问控制;

TCC 服务的一阶段 Try 操作预留资源之后,在二阶段操作执行之前,预留的资源都不会被释放;如果此时其他分布式事务修改这些业务资源,会出现分布式事务的并发问题;

用户在实现 TCC 服务时,需要考虑业务数据的并发控制,尽量将逻辑锁粒度降到最低,以最大限度的提高分布式事务的并发性;

6 Hmily

Hmily (How much I love you)

高性能分布式事务 tcc 开源框架。基于 JAVA 语言来开发(JDK1.8),支持 dubbo,springcloud,motan 等 rpc 框架进行分布式事务。

框架特性

  • 支持嵌套事务 (Nested transaction support).
  • 采用 disruptor 框架进行事务日志的异步读写,与 RPC 框架的性能毫无差别。
  • 支持 SpringBoot-starter 项目启动,使用简单。
  • RPC 框架支持 : dubbo,motan,springcloud。
  • 本地事务存储支持 : redis,mongodb,zookeeper,file,MySQL
  • 事务日志序列化支持 :java,hessian,kryo,protostuff。
  • 采用 Aspect AOP 切面思想与 Spring 无缝集成,天然支持集群。
  • 内置经典的分布式事务场景 demo 工程,并有 swagger-ui 可视化界面可以快速体验。

6.1 Hmily 原理及流程图

原理图:

浅谈分布式事务及解决方案

流程图:

浅谈分布式事务及解决方案

 

7 参考文献

  • https://dromara.org/website/zh-cn/docs/hmily/index.html
  • https://houbb.Github.io/2018/10/30/hmily
  • https://developer.aliyun.com/article/609854
  • https://blog.csdn.NET/bjweimengshu/article/detAIls/86698036
  • https://blog.csdn.net/u014296316/article/details/90185589
作者:京东物流 宋乐
来源:京东云开发者社区 自猿其说 Tech 转载请注明来源


Tags:分布式   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
在Redis中如何实现分布式锁的防死锁机制?
在Redis中实现分布式锁是一个常见的需求,可以通过使用Redlock算法来防止死锁。Redlock算法是一种基于多个独立Redis实例的分布式锁实现方案,它通过协调多个Redis实例之间的锁...【详细内容】
2024-02-20  Search: 分布式  点击:(47)  评论:(0)  加入收藏
手动撸一个 Redis 分布式锁
大家好呀,我是楼仔。今天第一天开工,收拾心情,又要开始好好学习,好好工作了。对于使用 Java 的小伙伴,其实我们完全不用手动撸一个分布式锁,直接使用 Redisson 就行。但是因为这些...【详细内容】
2024-02-19  Search: 分布式  点击:(39)  评论:(0)  加入收藏
雪花算法详解与Java实现:分布式唯一ID生成原理
SnowFlake 算法,是 Twitter 开源的分布式 ID 生成算法。其核心思想就是:使用一个 64 bit 的 long 型的数字作为全局唯一 ID。在分布式系统中的应用十分广泛,且 ID 引入了时间戳...【详细内容】
2024-02-03  Search: 分布式  点击:(50)  评论:(0)  加入收藏
Python分布式爬虫打造搜索引擎
简单分布式爬虫结构主从模式是指由一台主机作为控制节点负责所有运行网络爬虫的主机进行管理,爬虫只需要从控制节点那里接收任务,并把新生成任务提交给控制节点就可以了,在这个...【详细内容】
2024-01-25  Search: 分布式  点击:(58)  评论:(0)  加入收藏
分布式事务框架选择与实践
分布式事务是处理跨多个服务的原子操作的关键概念,而选择适合应用场景的框架对于确保事务一致性至关重要。以下是几个常见的分布式事务框架,并讨论它们的使用和实践。1. XA协...【详细内容】
2024-01-05  Search: 分布式  点击:(96)  评论:(0)  加入收藏
分布式场景下的事务机制
事务消息是RocketMQ的一个非常特色的高级特性,它的基础诉求是通过RocketMQ的事务机制,来保证上下游的数据⼀致性。我们在单机版本下面只需要在业务方法上加上对应的事务就可以...【详细内容】
2023-12-26  Search: 分布式  点击:(120)  评论:(0)  加入收藏
分布式存储系统在大数据处理中扮演着怎样的角色?
如果存储节点本身可以定制,则通常会让其支持部分计算能力,以利用数据的亲和性,将部分计算下推到相关的存储节点上。如果存储是云上的 S3 等对象存储,无法定制,则通常会将数据在计...【详细内容】
2023-12-19  Search: 分布式  点击:(48)  评论:(0)  加入收藏
MongoDB与大数据处理:构建高性能分布式数据库
MongoDB是一种非关系型数据库,具有高度灵活性和可扩展性。在处理大量数据时,索引的优化是提升查询性能的关键。下面将介绍一些MongoDB索引优化的指南,帮助用户更好地利用索引来...【详细内容】
2023-12-18  Search: 分布式  点击:(71)  评论:(0)  加入收藏
聊一聊雪花算法与分布式ID生成
生成全局唯一ID的雪花算法原理雪花算法是一种用于生成全局唯一ID的算法,最初由Twitter开发,用于解决分布式系统中生成ID的问题。其核心思想是将一个64位的长整型ID划分成多个...【详细内容】
2023-12-12  Search: 分布式  点击:(132)  评论:(0)  加入收藏
Redis分布式锁常见坑点分析
日常开发中,基于 Redis 天然支持分布式锁,大家在线上分布式项目中都使用过 Redis 锁。本文主要针对日常开发中加锁过程中某些异常场景进行讲解与分析。本文讲解示例代码都在 h...【详细内容】
2023-12-11  Search: 分布式  点击:(111)  评论:(0)  加入收藏
▌简易百科推荐
对于微服务架构监控应该遵守的原则
随着软件交付方式的变革,微服务架构的兴起使得软件开发变得更加快速和灵活。在这种情况下,监控系统成为了微服务控制系统的核心组成部分。随着软件的复杂性不断增加,了解系统的...【详细内容】
2024-04-03  步步运维步步坑    Tags:架构   点击:(5)  评论:(0)  加入收藏
大模型应用的 10 种架构模式
作者 | 曹洪伟在塑造新领域的过程中,我们往往依赖于一些经过实践验证的策略、方法和模式。这种观念对于软件工程领域的专业人士来说,已经司空见惯,设计模式已成为程序员们的重...【详细内容】
2024-03-27    InfoQ  Tags:架构模式   点击:(13)  评论:(0)  加入收藏
哈啰云原生架构落地实践
一、弹性伸缩技术实践1.全网容器化后一线研发的使用问题全网容器化后一线研发会面临一系列使用问题,包括时机、容量、效率和成本问题,弹性伸缩是云原生容器化后的必然技术选择...【详细内容】
2024-03-27  哈啰技术  微信公众号  Tags:架构   点击:(10)  评论:(0)  加入收藏
DDD 与 CQRS 才是黄金组合
在日常工作中,你是否也遇到过下面几种情况: 使用一个已有接口进行业务开发,上线后出现严重的性能问题,被老板当众质疑:“你为什么不使用缓存接口,这个接口全部走数据库,这怎么能扛...【详细内容】
2024-03-27  dbaplus社群    Tags:DDD   点击:(11)  评论:(0)  加入收藏
高并发架构设计(三大利器:缓存、限流和降级)
软件系统有三个追求:高性能、高并发、高可用,俗称三高。本篇讨论高并发,从高并发是什么到高并发应对的策略、缓存、限流、降级等。引言1.高并发背景互联网行业迅速发展,用户量剧...【详细内容】
2024-03-13    阿里云开发者  Tags:高并发   点击:(6)  评论:(0)  加入收藏
如何判断架构设计的优劣?
架构设计的基本准则是非常重要的,它们指导着我们如何构建可靠、可维护、可测试的系统。下面是这些准则的转换表达方式:简单即美(KISS):KISS原则的核心思想是保持简单。在设计系统...【详细内容】
2024-02-20  二进制跳动  微信公众号  Tags:架构设计   点击:(36)  评论:(0)  加入收藏
详解基于SpringBoot的WebSocket应用开发
在现代Web应用中,实时交互和数据推送的需求日益增长。WebSocket协议作为一种全双工通信协议,允许服务端与客户端之间建立持久性的连接,实现实时、双向的数据传输,极大地提升了用...【详细内容】
2024-01-30  ijunfu  今日头条  Tags:SpringBoot   点击:(9)  评论:(0)  加入收藏
PHP+Go 开发仿简书,实战高并发高可用微服务架构
来百度APP畅享高清图片//下栽のke:chaoxingit.com/2105/PHP和Go语言结合,可以开发出高效且稳定的仿简书应用。在实现高并发和高可用微服务架构时,我们可以采用一些关键技术。首...【详细内容】
2024-01-14  547蓝色星球    Tags:架构   点击:(115)  评论:(0)  加入收藏
GraalVM与Spring Boot 3.0:加速应用性能的完美融合
在2023年,SpringBoot3.0的发布标志着Spring框架对GraalVM的全面支持,这一支持是对Spring技术栈的重要补充。GraalVM是一个高性能的多语言虚拟机,它提供了Ahead-of-Time(AOT)编...【详细内容】
2024-01-11    王建立  Tags:Spring Boot   点击:(124)  评论:(0)  加入收藏
Spring Boot虚拟线程的性能还不如Webflux?
早上看到一篇关于Spring Boot虚拟线程和Webflux性能对比的文章,觉得还不错。内容较长,抓重点给大家介绍一下这篇文章的核心内容,方便大家快速阅读。测试场景作者采用了一个尽可...【详细内容】
2024-01-10  互联网架构小马哥    Tags:Spring Boot   点击:(115)  评论:(0)  加入收藏
站内最新
站内热门
站内头条