微服务·数据一致-事务与分布式事务

news2025/1/13 15:59:05

微服务·数据一致-事务与分布式事务

概述

事务是计算机科学和数据库管理中的一个关键概念,用于确保数据的一致性和可靠想。事务管理是大多数应用程序和数据库系统中不可或缺的一部分。分布式事务扩展了事务的概念,用于多个分布式系统和服务的数据一致性管理。本调查报告将深入探讨事务和分布式事务的概念、特性、类型和应用,以及事务处理的最佳时间

事务

什么事事务

事务是一组数据库操作的逻辑单元,要么全部成功执行,要么全部失败回滚,以保证数据的一致性和完整性。事务遵循ACID属性,即原子性(Atomicity)、一致性(Consistency)隔离性(Isolation)和持久性(Durability)。

ACID属性

  • 原子性(Atomicity):事务中的所有操作要么全部成功,要么全部失败。如果发生故障或异常,事务应该会滚到起始状态。
  • 一致性(Consistency):事务将数据从一个一致状态转移到另一个一致状态。在事务结束后,所有约束和规则都应得到满足
  • 隔离性(Isolation):事务应该在隔离的环境中执行,即使多个事务并发执行,也不相互干扰。数据库管理系统提供不同级别的隔离度。
  • 持久性(Durability):一旦事务提交,其结果应该用具保存在数据库中,技术发生故障也不会丢失

如何保证原子性

innodb利用undo log实现原子性。undo log名为回滚日志,是实现原子性的关键,当事务回滚是能够撤销虽有已经执行成功的sql语句,它需要记录你要回滚的相应的日志信息。比如:delete一个数据的时候,就需要记录这条数据的信息,回滚的时候insert这条旧数据。当事务执行功能失败或调用rallback,导致事务需要回滚,便可以利用undo log中的信息将数据回滚到修改之前的样子。

如何保证持久性

在修改数据的时候,Mysql先把磁盘上的数据加载到内存中,在内存中对数据修改,再刷到磁盘中。如果在刷盘前宕机,内存中的数据就会丢失。

  • 解决思路:事务提交前直接把数据写入磁盘中。
    引入问题:性能损耗严重,只修改一个页(16k)里面的一个字节,就需要把整个页面刷入磁盘。另外一个事务的SQL可能涉及到多个数据页的修改,存在随机IO的可能,速度会更慢。
  • 解决思路:使用redo log
    修改数据的时候,不仅内存中操作,还会在redo log中记录这次操作,当事务提交的时候会将redo log日志进行刷盘。当数据库宕机重启的时候,会将redo log中的内容恢复到数据库中,再根据undo log和binlog内容决定回滚数据还是提交数据。

一条数据的更新流程

在这里插入图片描述

事务并发带来的问题及隔离级别

当事务并发的时候会带来一下问题:

  • 脏读:一个事务访问到另一个事务未提交的数据。
  • 不可重复读:一个事务多次读取同一个数据的过程中,数值发生变化。
  • 幻读:一个事务多次读取同一个数据的过程中, 全局数据(表的结构)发生了改变。

为了解决并发事务带来的问题,提供了事务的隔离级别:

  • 读未提交:允许读取未提交的内容,这种级别下查询不会加锁,存在脏读、幻读、不可重复的问题。
  • 读已提交:只允许读取已提交的内容,但是仍然会存在幻读、不可重复度的问题。
  • 可重复读:用行级锁来保证一个事务在相同查询条件下两次查询结果一致 , 可以避免脏读, 不可重复读, 但无法避免幻读。(Innodb解决了幻读问题)
  • 串行化:用表级锁来保证所有事务串行化, 可以防止所有的异常情况, 但牺牲了数据库的并发性。

事务隔离级别实现的原理

  • 读未提交:
    • 事务对当前读的数据不加锁,都是当前读。
    • 事务在更新数据的瞬间,必须先对其加行级共享锁,直到事务结束才释放。
  • 读已提交:
    • 事务对当前读的数据不加锁,是快照读。
    • 事务在更新数据的瞬间,必须先对其加行级排他锁(record)直到事务结束才释放。
  • 可重复读:
    • 事务对当前读的数据不加锁,且是快照读。
    • 事务在更新数据的瞬间,必须对其加行级排他锁(record、gap、nest-key),直到事务结束才释放
  • 串行化:
    • 事务在读数据时,必须先对其加表级共享锁,直到数据结束才释放,都是当前读。
    • 事务在更新数据是,必须先对其加表级排他锁,直到事务结束才释放。

Spring中的事务管理

事务的传播行为

  • PROPAGATION_REQUIRED:默认的事务事务传播行为,如果存在当前事务,则加入当前事务,如果不存在,则创建一个新的。
    • 如果外部方法没有开启事务,PROPAGATION_REQUIRED修饰的内部方法会开启自己的事务,且开启的事务相互独立,互不干扰。
    • 如果外部方法开启了事务,且是PROPAGATION_REQUIRED,则外部和内部方法属于一个事务,只要一个方法回滚,整个事务都需要回滚,即A(外部方法)影响B(内部方法),B影响A。
  • PROPAGATION_REQUIRED_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
    • 不管外部方法是否开启事务,PROPAGATION_REQUIRED_NEW修饰的方法都会开启自己的事务。外部方法的事务与内部方法的事务相互独立,互不干扰。即A不影响B,B不影响A。
  • PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务,否则以非事务方式运行。
  • PROPAGATION_NOT_SUPPORTS:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  • PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
  • PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
  • PROPAGATION_NESTED:如果当前存在事务,就在当前事务内执行。否则就执行与PROPAGATION_REQUIRED类似的操作
    • A影响B,B不影响A。

事务失效的几种情况

  • 抛出事务不支持的异常
    Spring事务默认支持RuntimeException,如果抛出的异常为RuntimeException及其子类异常,事务均可生效。如果是抛出的Exception异常,则失效。解决方案:指定Spring事务异常捕获类型@Transactional(rollbackFor = Exception.class)或抛出spring事务支持的异常类型。
  • 使用了try-catch
    异常被try-catch捕获,导致事务失效。解决方案:在catch中抛出Spring事务支持的异常。
  • 事务方法为私有方法
    Spring声明式事务是基于动态代理实现的,private方法不能被代理,事务不生效。此外static方法属于类,不属于任何对象,也不会被代理,事务不生效。final方法无法被重写,也不能被代理,事务不生效。
  • 未被Spring管理的类
    Spring实现对象的动态代理,首先这个对象要交给Spring管理
  • 一个方法调用本类的另一个方法
    @Transactional基于AOP实现,而AOP又是基于动态代理实现,直接调用本类方法或使用this调用本类方法,均不是Spring的代理对象,无法实现动态代理,事务也就不会生效。
  • 数据表不支持事务
  • Spring事务传播级别设置为不支持事务

分布式事务

什么是分布式事务

分布式事务是在分布式系统中维护数据一致性的方式。它扩展了ACID事务的概念,以跨越多个分布式服务、数据库和资源的范围来保证数据的一致性。

分布式事务面临的挑战

  • 网络延迟:跨网络执行事务可能导致较高的延迟,影响性能。
  • 故障处理:分布式系统中的节点故障可能导致事务的不一致状态,需要复杂的故障处理机制。
  • 并发控制:多个事务同时访问和修改共享数据需要有效的并发控制机制。

分布式事务的历史与发展

分布式事务的历史和发展经历了多个阶段,从早期的两阶段提交到最近的新兴分布式数据库和NoSQL解决发方案。

  • 两阶段提交(2PC):
    • 1980年代末到1990年代初,提出了两阶段提交。两阶段提交通过协调者和参与者的协作,确保在多个分布式数据库之间的事务具有原子性和一致性。
    • 2PC的问题在于它可能导致性能瓶颈和阻塞,因为在第二阶段需要等待所有参与者的确认。
  • 三阶段提交(3PC)
    • 为了阶段2PC的一些问题,提出了三阶段提交。3PC引入了一个预提交节点,以减少阻塞问题,然而它仍然存在某些情况下无法解决的问题。
  • XA事务
    • XA(eXtended Architecture)是一种用于分布式事务的标准,由X/Open组织制定。XA事务使用了分布式管理器(TransactionManager)来协调多个资源管理器(Resource Manager)的事务。
    • XA事务提供了分布式事务的一些标准化机制,但它在性能可伸缩性方面仍然有限制
  • Sage模式
    • Sage是一种分布式事务模型,将长事务拆分成一系列小事务,并使用补偿事务来处理部分失败。Sage模式在微服务架构中得到广泛应用,以提高系统的可伸缩性和可恢复性。
  • NoSQL数据库
    • 随着分布式计算和大数据的兴起,出现了各种新兴的NoSQL数据库,如Cassandra、MongoDB和Couchbase。这些数据库通过采用了最终一致性的模型,提高性能和可用性。
    • NoSQL数据库的出现使得开发人员需要重新考虑分布式事务的模型,并引用了新的解决方案,如CRDTs(Confict-Free Replicated Data Types)。
  • 新兴分布式数据库
    • 近年来,出现了一些性能的分布式数据库系统,如Google的Spanner和CockroachDB,它们旨在提供全球分布式事务的支持。这些系统使用全球分布式的时间同步和意义性协议来实现强一致性的分布式事务。
  • 区块链技术
    • 区块链技术引入了一种分布式账本的概念,其中的交易具有强一致性和不可变性。这使得区块称为一种分布式事务的潜在选择,尤其是金融和合同领域。

分布式事务处理方法

2PC

两阶段提交是一种强一致性设计,它引入一个事务协调者的角色协调管理各个参与者的提交和回滚。

  • 准备阶段(Phase1 - Prepare Phase)
    • 协调者向所有参与者发送事务准备请求
    • 参与者收到请求后,会执行事务的准备操作,并准备好事务的状态(提交或回滚)保存到本地
    • 参与者在准备完成后向协调者发送准备完成的通知,同时将本地准备状态持久化
  • 提交阶段(Phase2 - Commit Phase)
    • 协调者在收到所有参与者的准备完成通知后,如果所有参与者都准备就绪,将向所有参与者发送事务提交请求。
    • 参与者接受到提交请求后,会执行事务的提交操作,将事务永久性的应用到系统中并释放之前的资源。
    • 参与者在完成提交后发送提交完成的通知。
  • 回滚阶段(Phase2 - Rollback Phase)
    • 如果在准备阶段任何参与者没有准备好,或者有参与者在提交阶段失败,协调者将会向所有参与者发送事务回滚请求。
    • 参与者接受到回滚请求后,会执行事务回滚操纵,将之前的操作撤销,并释放资源。
    • 参与者在完成回滚后向协调者发送回滚完成的通知。

2PC存在的问题

  • 同步阻塞:所有的参数者都是事务同步阻塞型的,当参与者占有公共资源时,其他三方访问公共资源不得不处于阻塞状态。
  • 单点故障:一旦协调者发生故障,系统不可用。
  • 数据不一致:当协调者发送commit之后,有的参与者收到commit消息,事务执行成功,有的没有收到,处于阻塞状态,这段时间会产生数据不一致情况。
  • 不确定性:当协调者发送commit后,并且此时只有一个参与者收到commit,那么当该参与者与协调器同时宕机后,重新选举的协调者无法确定该消失是否提交成功。

2PC的优势在于对业务没有侵入,可以利用数据库自身机制急性事务的提交和回滚。常见的机遇2PC的具体落地方案有JTA(XA规范)和Seata(AT模式)

3PC

三阶段提交是二阶段提交的改进版本,在协调者和参与者都引入了超时机制,在2PC中的准备阶段和提交阶段增加了一个预提交阶段。

  • 准备阶段(CanCommit):协调者向各个参与者发送请求,询问是否可以执行事务,但并不是执行事务。
  • 预提交阶段(PreCommit):如果从协调者得到反馈是满足执行条件,那么就发送预提交请求,并开始执行事务;如果从协调者得到返回时不满足执行条件或者超时,则发送事务中断请求。
  • 提交阶段(DoCommit):如果预提交阶段发送的是预提交请求,那么正常提交事务;如果预提交阶段发送的是事务中断请求,那么直接中断事务。在这里插入图片描述
    相对于 2PC,3PC 主要解决的单点故障问题,并减少阻塞,因为一旦参与者无法及时收到来自协调者的信息之后,他会默认执行 commit。而不会一直持有事务资源并处于阻塞状态。但是这种机制也会导致数据一致性问题,因为,由于网络原因,协调者发送的中断响应没有及时被参与者接收到,那么参与者在等待超时之后执行了 commit 操作。这样就和其他接到中断命令并执行回滚的参与者之间存在数据不一致的情况。而且 3PC 整体的交互过程更长,性能也会有所下降。
    3PC 目前似乎只存在于理论,还没有具体落地方案。

TCC

2PC和3PC都是依赖于数据库的事务提交和回滚,但是有时候很多业务并不知涉及到数据库,可能会发送短信、消息等,而TCC就是属于业务层面的分布式应用。
TCC方案分为Try-Confirm-Cancel三个阶段,属于补偿性分布式事务。

  • Try阶段:完成所有业务检查(一致性),预留业务资源(隔离性)
  • Confirm阶段:确认执行业务操作,不再做任何业务检查,只使用Try阶段预留的业务资源。
  • Cancel阶段:取消Try阶段预留的业务资源。
    在这里插入图片描述
    Try阶段失败了会执行Cancel,Confirm阶段失败会不断进行重试,或者进行人工干预。
    TCC需要根据每个场景和业务逻辑来设计相应的操作,所以很大程度增加了业务代码的复杂度,对业务有很大的侵入。但是没有资源阻塞,每一个方法都是直接提交事务的,如果出错是通过业务层面的Cancel来进行补偿,所以也称补偿事务方法。

TCC要注意的几个问题

  • 幂等问题:因为网络调用无法保证请求一定能到达,所以都会有重试机制,因此对于Try、Confirm、Cancel三个方法都需要幂等实现,避免重复执行产生错误。
  • 空回滚问题:指的是Try方法由于网络问题没有收到超时了,此时事务管理器就会发出Cancel命令,那么需要支持Cancel在没有执行Try的情况下能正常Cancel。
  • 悬挂问题:这个问题也是指Try方法由于网络阻塞超时出发了事务管理器发出了Cannel命令,但是执行了Cancel命令之后,Try请求到了。所以空回滚之后还得记录一下,防止Try的再调用。

可靠消息最终一致性方案

RocketMQ4.3之后的版本正式支持事务消息。

  • 服务A(生产者)向Broker(消息中间件)发送一个HalfMessage(半消息:消息发送到Broker端,但是消息的状态被标记为“不能投递”,即消费者看不到)
  • 半消息发送成功后,服务A执行本地事务。
  • 事务执行成功,向Broker发送Commit命令,此时半消息就变成了可以被消费的消息;如果失败,则发送一个RollBack命令,该消息会被删除。
  • 服务B(消费者)收到消息后消费该消息即可。
  • 在RocketMQ没有收到服务A确认状态的消息,那么半消息会自宋定时轮询毁掉接口,询问这个处理的处理情况。
  • 服务B在执行的过程中也可能会失败,这时需要重试,一直执行不成功也需要人工介入,同时也需要保证服务B方法的幂等性。

应用场景

分布式事务适用于需要数据一致性的多个应用场景,包括:

  • 电子商务:确保订单处理、支付和库存管理等操作的一致性。
  • 金融服务:跨银行交易、交易清算和资金阶段的一致性管理。
  • 物流和供应链:跨多个仓库、配送中心和供应商的库存和订单管理。
  • 在线游戏:多玩家游戏中的虚拟经济和资源管理。

结论

事务和分布式事务是分布式系统和数据库管理中的关键概念,了解了它们的原则、属性和实现方式对于构建高可用、高性能和数据一致性的应用程序至关重要。在选择分布式事务方案是,需要根据应用的的要求权衡性能、复杂度和一致性。

引用

https://www.cnblogs.com/chengxy-nds/p/14046856.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/998728.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1、java基本语法

1.、标识符、关键字、注释 标识符:对类、对象、变量、方法、数组等起个名字。 合法的标识符: 由字母、数字、下划线“_”组成,并且首字符不能是数字。不能把java关键字和保留字作为标识符。标识符区分大小写字母。 理论上只要满足上面三个…

Vuex -访问(modules)模块中的 state mutations actions getters

文章目录 四大核心复习一、获取模块内的state数据1.目标:2.使用模块中的数据3.代码示例 二、获取模块内的getters数据1.目标:2.语法:3.代码演示 三、获取模块内的mutations方法1.目标:2.注意:3.调用方式:4.…

LRTA*(Learning-RTA*)

1、基本概念 LRTA* 算法是对RTA* 算法的改进,在RTA* 的原论文中,提到了: Unfortunately, while RTA* as described above is ideally suited to single problem solving trials, it must be modified to accommodate multi-trial learning.…

集成学习-树模型

可以分为三部分学习树模型: 基本树(包括 ID3、C4.5、CART).Random Forest、Adaboost、GBDTXgboost 和 LightGBM。 基本树 选择特征的准则 ID3:信息增益max C4.5:信息增益比max CART:基尼指数min 优缺…

【uniapp关联unicloud,阿里云云服务空间】unicloud本地调试服务启动失败:当前项目未关联unicloud服务空间,请调整后重新运行,已解决

最近开发app项目,很多都是第一次上手 1、在Hbuider中运行项目,出现如下提示 2、项目根目录下已有uniCloud文件夹 3、如果云开发环境未创建,可以右击项目,选择创建uniCloud云开发环境 4、创建好的目录如下,index.js中…

图解三重积分的对称性

1.图解三重积分的对称性 关于三重积分详见:三重积分(Triple Integral) 三重积分的对称性原理与二重积分类似,关于二重积分的对称性详见:图解二重积分的对称性 被积函数 f ( x , y , z ) f(x,y,z) f(x,y,z)可以有不同的物理意义,…

查询设计之查询条件对结果的影响

在sql使用中,最常用的就是查询。 在实践过程中,丰富的查询场景也使得查询sql有多种写法,不同的写法会带来不同的效果 以下,就查询条件对结果的影响。 一、数据 二、需求 把查询 type A’的 user 以及 type ‘A’ 的 department…

网络爬虫的意义:连接信息世界的纽带

本文将探讨网络爬虫的意义及其在连接信息世界中的重要作用。网络爬虫作为一种自动化程序,通过收集和提取互联网上的数据,为搜索引擎、数据分析和机器学习等领域提供了宝贵的资源。同时,我们也将探讨网络爬虫的伦理和法律责任,以及…

5、DVWA——文件上传

文章目录 一、文件上传原理二、low2.1 源码分析2.2 通关步骤 三、medium3.1 源码分析3.2 通关思路 四、high4.1 源码分析4.2 通关思路 一、文件上传原理 文件上传漏洞一般指用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力。文件上传…

C语言经典100例题(45)--学习使用register定义变量的方法

目录 题目 问题分析 代码 运行结果 题目 学习使用register定义变量的方法 问题分析 register是做声明的,为了提高效率。 register变量不能做取地址运算符&操作。 声明变量具有register储类型就要求编译器把变量存储在寄存器中,而不是像其他变量…

第4篇 vue的基本语法操作以及组件,声明周期,路由的操作

一 vue常用操作案例 1.1 事件渲染 1.数据渲染的方式:使用插值表达式{{}}进行数据渲染 2.数据渲染的方式:以使用 v-bind指令,它的简写的形式就是一个冒号(:),v-bind 特性被称为指令。指令带有前缀 v- 代…

OLED透明屏交互技术:开创未来科技的新篇章

OLED透明屏交互技术作为一项前沿的科技创新,正在以其高透明度、触摸和手势交互等特点,引领着未来科技的发展。 不仅在智能手机、可穿戴设备和汽车行业有着广泛应用,还在广告和展示领域展现出巨大的潜力。 那么,尼伽在这篇文章中将…

无涯教程-JavaScript - DDB函数

描述 DDB函数使用双倍余额递减法或您指定的某些其他方法返回指定期间内资产的折旧。 语法 DDB (cost, salvage, life, period, [factor])争论 Argument描述Required/OptionalCostThe initial cost of the asset.RequiredSalvage 折旧结束时的价值(有时称为资产的残值)。 该…

三、lock类的编写与解析 —— TinyWebServer

lock类的编写与解析 —— TinyWebServer 一、前言 这个类的作用作者已经给了解释 —— “多线程同步,确保任一时刻只能有一个线程能进入关键代码段.” 对于这句话其实看了,会有似懂非懂的感觉,然后写代码的时候,就会完全不懂。其…

分享一个开发者和设计者的免费图标库

图标是现代界面设计的不可或缺的一部分,无论是移动应用、网页设计还是软件界面。然而,许多开发者和设计师都面临着一个共同的挑战:寻找高品质、开源且免费的矢量图标资源。在这个领域,Yesicon 脱颖而出,成为了一个备受…

【计算机网络】UDP数据包是如何在网络中传输的?

List item 创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 更多计算机网络知识专栏&#xff1a;计算机网络&#x1f525;…

【性能测试】中间件优化

1、Tomcat 优化连接数、线程池 打开tomcat安装目录\conf\server.xml文件&#xff0c;在server.xml中 有以下配置&#xff1a; tomcat HTTP/1.1 <Connector port"8080" protocol"HTTP/1.1" maxThreads"1000" acceptCount"1500" c…

Python网络爬虫库:轻松提取网页数据的利器

网络爬虫是一种自动化程序&#xff0c;它可以通过访问网页并提取所需的数据。Python是一种流行的编程语言&#xff0c;拥有许多强大的网络爬虫库。在本文中&#xff0c;我们将介绍几个常用的Python网络爬虫库以及它们的使用。 Requests库 Requests是一个简单而优雅的HTTP库&…

mysql中GROUP_CONCAT函数详解

GROUP_CONCAT是MySQL中的一个聚合函数&#xff0c;它用于将多行数据按照指定的顺序连接成一个字符串&#xff0c;并返回结果。下面是对GROUP_CONCAT函数的详解&#xff1a; 语法&#xff1a; GROUP_CONCAT([DISTINCT] expr [,expr …] [ORDER BY {unsigned_integer | col_name…

揭秘动态网页与JavaScript渲染的处理技巧

大家好&#xff01;作为一名互联网技术爱好者&#xff0c;今天我要和大家分享一个关于Python数据采集的重要技巧——处理动态网页与JavaScript渲染&#xff01;这是一项在数据获取领域中非常关键的技能&#xff0c;让我们一起揭秘它的神秘面纱吧&#xff01; 首先&#xff0c;让…