事务

5 minute read

spring事务 https://juejin.cn/post/6844903801841778702

1、@Transactional注解可以作用于哪些地方? @Transactional 可以作用在接口、类、类方法。

作用于类:当把@Transactional 注解放在类上时,表示所有该类的public方法都配置相同的事务属性信息。 作用于方法:当类配置了@Transactional,方法也配置了@Transactional,方法的事务会覆盖类的事务配置信息。 作用于接口:不推荐这种使用方法,因为一旦标注在Interface上并且配置了Spring AOP 使用CGLib动态代理,将会导致@Transactional注解失效

2、@Transactional注有哪些属性? propagation 代表事务的传播行为,默认值为 Propagation.REQUIRED

Propagation.REQUIRED:如果当前存在事务,则加入该事务,如果当前不存在事务,则创建一个新的事务。 ( 也就是说如果A方法和B方法都添加了注解,在默认传播模式下,A方法内部调用B方法,会把两个方法的事务合并为一个事务 ) Propagation.SUPPORTS:如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行。 Propagation.MANDATORY:如果当前存在事务,则加入该事务;如果当前不存在事务,则抛出异常。 Propagation.REQUIRES_NEW:重新创建一个新的事务,如果当前存在事务,暂停当前的事务。 ( 当类A中的 a 方法用默认Propagation.REQUIRED模式,类B中的 b方法加上采用 Propagation.REQUIRES_NEW模式,然后在 a 方法中调用 b方法操作数据库,然而 a方法抛出异常后,b方法并没有进行回滚,因为Propagation.REQUIRES_NEW会暂停 a方法的事务 ) Propagation.NOT_SUPPORTED:以非事务的方式运行,如果当前存在事务,暂停当前的事务。 Propagation.NEVER:以非事务的方式运行,如果当前存在事务,则抛出异常。 Propagation.NESTED :和 Propagation.REQUIRED 效果一样。

3、isolation 属性 isolation :事务的隔离级别,默认值为 Isolation.DEFAULT。

Isolation.DEFAULT:使用底层数据库默认的隔离级别。 Isolation.READ_UNCOMMITTED Isolation.READ_COMMITTED Isolation.REPEATABLE_READ Isolation.SERIALIZABLE

@transactional注解在什么情况下会失效,为什么。 1,@Transactional 注解应该只被应用到 public 可见度的方法上

4、同一个类中方法调用,导致@Transactional失效 开发中避免不了会对同一个类里面的方法调用,比如有一个类Test,它的一个方法A,A再调用本类的方法B(不论方法B是用public还是private修饰), 但方法A没有声明注解事务,而B方法有。则外部调用方法A之后,方法B的事务是不会起作用的。这也是经常犯错误的一个地方。

那为啥会出现这种情况?其实这还是由于使用Spring AOP代理造成的,因为只有当事务方法被当前类以外的代码调用时,才会由Spring生成的代理对象来管理。

5、数据库引擎不支持事务

分布式事务 分布式系统往往做到的结果是实现最终一致性,而ACID事务特性不满足分布式系统的可用性要求,所以分布式系统由CAP思想转向为BASE思想,即做到 BA basiclly available/S soft state/E eventually consistency

完全版的事务代价很大,因为事务不允许中间状态的产生,所以事务中所涉及的共享资源必须是不能被访问的,那么其它消费者必须是阻塞状态、高并发时期共享资源被长时间的占用,会导致系统不可用。比如高峰期的厕所

分布式事务、常见的有2PC、3PC、TCC、事务消息

2PC和3PC的明白文 https://segmentfault.com/a/1190000012534071

两阶段提交2PC 两阶段提交是计算机网络尤其是数据库领域内,为了使基于分布式系统架构下的所有节点在进行事务处理时能够保持原子性和一致性而设计的一种算法。 绝大部分的关系型数据库都是采用两阶段提交协议来完成分布式事务处理。

2PC的大致流程是什么? 集群有协调者和参与者两种角色,协调者是单点,流程大致分为两步,执行事务和提交事务两个阶段 1,首先,协调者向所有参与者发送事务内容,询问是否可以执行事务,等待参与者的响应;参与者执行事务操作,记录undo和redo日志; 参与者如果执行成功,反馈给协调者Yes,否则返回No; 2,如果参与者都反馈Yes,协调者向全部参与者发送提交事务的请求,参与者执行事务提交并反馈协调者ACK信息,协调者收到所有参与者ACK反馈后,完成事务 如果有一个参与者反馈No或等待参与者反馈超时时,协调者向所有参与者发送回滚请求,参与者利用undo日志执行事务回滚并向协调者反馈结果,协调者收到所有参与者ACK之后,完成事务回滚。

2PC的应用场景? 绝大部分的关系型数据库都是采用两阶段提交协议来完成分布式事务处理。

2PC的优点和缺点? 优点:简单,容易实现 缺点: 1、同步阻塞 在事务提交的执行过程,所有参与该事务的参与者都处于等待状态 2、协调者单点问题 如果协调者宕机,集群无法提供服务 3、数据不一致 当协调者发送的提交事务的请求没有成功发送到全部参与者的时候,数据会处于不一致的状态 4、保守 需要全部参与者全部成功才算成功

三阶段提交3PC 3PC的大致流程是什么? 3PC分为3个阶段,canCommit/preCommit/doCommit 3PC相比于2PC,增加了一个preCommit阶段,当所有参与者收到preCommit后,并不执行动作,直到收到commit或超过一定时间后才完成此操作。 canCommit 首先,协调者向各参与者询问是否可以执行事务提交操作,如果参与者认为自身可以顺利执行,发送Yes给协调者,否则发送No; preCommit 1、如果协调者收到了所有参与者反馈并且都是Yes,则协调者向所有参与者发送preCommit请求,参与者执行事务操作并反馈给协调者执行结果 2、如果协调者收到了No或等待超时,则协调者向所有参与者发送abort请求,参与者无论是收到abort请求或等待超时,都会中断事务 doCommit 协调者等待preCommit阶段的参与者的执行结果 1,如果协调者收到所有参与者的Yes结果,则向所有参与者发送doCommit请求,参与者收到请求后,提交事务并反馈给协调者结果,协调者完成事务 2,如果协调者等待超时或收到No,协调者向所有参与者发送回滚请求,参与者执行并反馈给协调者,事务终止 在doCommit阶段,如果协调者因为网络问题导致参与者迟迟不能收到协调者的commit或rollback请求,参与者不会像两阶段提交那样 陷入阻塞,而是等待超时后继续执行commit,相比于两阶段虽然降低了同步阻塞,但仍然无法避免数据的不一致。

为什么会有3PC,相比于2PC,优化了什么? 针对于2PC的阻塞问题,三阶段提交协议通过增加preCommit阶段以及超时策略来减少集群的阻塞时间,提升系统性能。

2PC和3PC的对比? 2PC和3PC都是解决数据一致性的协议,3PC相比于2PC协议复杂了许多,但仍然解决不了数据一致性问题,建议优化2PC的具体实现

2PC 两阶段提交,有协调者和参与者两个角色,两阶段是准备阶段和提交阶段 准备阶段是协调者向各参与者发送准备命令,这个阶段除了事务的提交啥都做了 提交阶段是协调者看各参与者准备阶段是否ok,如果ok,协调者就向各个参与者发送提交命令,如果有一个不ok,就发送回滚命令

2pc是一种强一致性的分布式事务,它是同步阻塞的,即参与者在收到提交或者回滚命令之前,所有参与者都相互等待,此时资源是锁定的状态,假设一个参与者卡了很久,其它参与者都要等待,产生长时间资源锁定状态下的阻塞。

2pc只适合数据库层面的事务,总体而言效率低,而且存在协调者单点故障,同时存在数据不一致的风险,例如某个参与者未收到提交命令,此时宕机了,恢复之后数据回滚,其它参与者实际都已经执行事务的提交,造成数据不一致

paxos https://www.cnblogs.com/binarylei/p/9906044.html paxos的流程是什么? paxos算法是让整个集群对某个值的变更达成一致,paxos算法也是一种强一致性算法,集群任何一个节点都可以提出要修改某个数据的提案,是否通过这个提案 取决于集群中是否有超过半数的节点同意,所以paxos算法要求集群中节点的数量是单数。 该算法有两种角色,proposer和acceptor 1,proposer提出一个提案,编号为N,此N大于这个proposer之前提出的提案编号,请求acceptor接受 2,如果N大于此acceptor之前接受的任何提案编号则接受,否则拒绝 3,如果proposer接受到的Yes响应占大多数,则proposer发出accept请求,此请求包含提案编号N,以及提案内容 4,如果acceptor在此期间没有收到任何编号大于N的提案,则接受此提案,否则忽略

为什么会出现paxos协议? 相比于2pc和3pc,解决了什么问题? 解决了协调者单点问题,同时也不像2pc需要全部参与者成功才能提交,同时依靠递增的提案编号,保证对于同一个值的在不同结点的修改提案就算是在接收方被乱序收到也是没有问题的。 在Paxos算法中,如果我们指定集群中同一时间只能有一个leader,并且要求所有节点都要投票呢?是的,我们就得到了2PC。2PC是Paxos的一个特例

raft协议是什么?它的大致流程是什么? raft协议强文:https://zhuanlan.zhihu.com/p/147691282 raft协议是paxos算法的一种简单实现,包括三种角色,leader/follower/candidate follower: 所有节点都从follower状态开始,如果没有收到leader消息,则变成candidate状态 candidate: 会向其它节点拉选票,如果得到大部分的票则成为leader,此过程为leader选举 leader:所有对系统的修改都会先经过leader raft协议大致分为两个过程: 1、leader选举 每个candidate随机经过一定时间都会提出选举方案,最近阶段中的票多者被选为Leader 2、同步log leader会找到系统中的各种时间发生的最新记录,强制所有follower刷新这个记录

raft协议的每个副本都会处于以下三种状态之一:leader/follower/candidate leader: 所有请求的处理者,leader接受client的更新请求,本地处理后再同步其它follower follower:从leader处接受请求,写入本地日志文件 candidate: 如果follower在一段时间内没有收到leader的心跳,则判断leader可能已经故障,此时启动选主过程,follower变成candidate,直到选主结束

raft协议与paxos的协议是一致的,如果follower接受不到leader的心跳,就会全部转化为candidate,然后candidate开始选主过程,选出leader之后所有 没选上的candidate退回follower状态,然后统一接受leader领导。

也就是说,只要leader不挂掉,只需要选举一次就可以了,后面大家默认信任选出来的leader。

在强leader的帮助下,raft将一致性问题分解为三个子问题: 1、leader选举 当已有的leader故障时必须选出一个新的leader 2、日志复制 leader接受客户端的命令,记录为日志,并复制给集群中的其它服务器,并强制其它节点的日志与leader保持一致 3、安全safety措施 通过一些措施保证系统的安全性、例如通过一些措施保证所有节点按照相同的顺序执行相同的命令

zab协议 zk集群使用zab协议来保证分布式事务的最终一致性,牺牲了ap

zab协议的流程是什么? zab协议定义了选举election、发现discovery、同步sync、广播broadcast四个阶段 选举是选出一个leader 发现、同步是当选主结束后,要做的数据恢复的阶段 广播是当leader和从机同步好数据以后,正常的主从同步从写数据的过程

leader 节点可以处理事务请求和非事务请求,follower 节点只能处理非事务请求,如果 follower 节点接收到非事务请求,会把这个请求转发给 Leader 服务器

集群的节点有3种类型,leader、follower、observer leader: 领导者 follower:接受提议的跟随者 observer:领导者的copy,不参与投票 leader 的投票过程,不需要 Observer 的 ack,也就是Observer 不需要参与投票过程,但是 Observer 必须要同步 Leader 的数据从而在处理请求的时候保证数据的一致性也就是说Observer 只负责加速读请求访问

从网上查询得知,工业界中三种协议的应用情况基本如下: 微信背后的高可用存储系统 PaxosStore 是基于 Multi Paxos 开发的 广为人知的高可靠的 kv 存储系统 etcd 用的 Raft 阿里的高性能存储 PolarFS 用到的 Raft 变种 ParallelRaft 协议 TiDB 用的 Raft ZAB 的名字就叫 ZooKeeper Atomic Broadcast,自然是 ZooKeeper 在用,没找到其他在用的,但是考虑到动物管理员恐怖的占有率,ZAB 协议也不容轻视

tcc分布式事务:业务层来实现对多个操作的原子性保证,强侵入式代码,需要业务耦合 开源tcc框架:ByteTCC,tcc-transaction,himly

https://cloud.tencent.com/developer/article/1477485 基于mq实现消息的最终一致性,前提需要保证下游服务对消息处理的幂等性

分布式系统往往只能妥协到最终一致性,保证数据最终的完整性和一致性,主要原因就是实力不允许…因为可用性为王。

RocketMQ 的事务消息也可以被认为是一个两阶段提交,简单的说就是在事务开始的时候会先发送一个半消息给 Broker。

rocket mq事务和kafka 事务 https://jishuin.proginn.com/p/763bfbd2bf26 Broker 会定时的向 Producer 来反查这个事务是否成功 Producer需要暴露一个接口,通过这个接口 Broker 可以得知事务到底有没有执行成功,没成功就返回未知,因为有可能事务还在执行,会进行多次查询。 如果成功那么就将半消息恢复到正常要发送的队列中,这样消费者就可以消费这条消息了。

rocket mq半消息队列

Kafka 的事务消息和 RocketMQ 的事务消息又不一样了,RocketMQ 解决的是本地事务的执行和发消息这两个动作满足事务的约束。 而 Kafka 事务消息则是用在一次事务中需要发送多个消息的情况,保证多个消息之间的事务约束,即多条消息要么都发送成功,要么都发送失败

Kafka 的事务基本上是配合其幂等机制来实现 Exactly Once 语义的,所以说 Kafka 的事务消息不是我们想的那种事务消息,RocketMQ 的才是。 kafka exactly once有且只能存在一种场景 Kafka 作为消息源,然后做了一番操作之后,再写入 Kafka 中

Updated:

Leave a comment