java面试题-微服务(二)---分布式事务和分布式锁

一、分布式事务

1、什么是分布式事务?

        分布式事务,指的是在分布式环境中,一个请求可能涉及到对多个数据库的写操作,要保证多数据库的一致性就需要用到分布式事务

2、分布式事务你知道哪些解决方案? 这些方案如何选型?

        常见的分布式事务解决方案:2PC,TCC,可靠消息最终一致性,最大努力通知

        2PC,它将整个事务流程分为两个阶段,P指的是准备阶段,C指的是提交阶段。它是一个阻塞协议,不适用于并发较高,事务生命周期长的分布式事务

        TCC,它是基于补偿性事务的AP系统的一种实现,补偿也就是说先按照预定方案执行,如果失败了就走补偿方案。它可以自己定义数据操作的粒度,但是对应用的侵入性强,可以用在登录送积分,送优惠券等等场景

        可靠消息最终一致性,指的是当事务发起方执行完本地事务后,就发出一条消息通知其他参与方,并且他们一定能接收到消息并处理事务。适合执行周期长,并且实时性要求不高的场景

        最大努力通知,是在不影响主业务的情况下,尽可能的保证数据的一致性,它适用于一些最终一致性敏感度低的业务,比如支付结果通知

3、什么是2pc?

DTP模型是Distributed Transaction Processing(‌分布式事务处理)‌的缩写,‌它是一套分布式事务的规范,‌旨在协调和管理跨多个资源或服务的事务处理。‌

DTP模型涉及三个主要角色:‌

  • AP(‌Application Program)‌:‌代表应用程序,‌即使用分布式事务的应用程序。‌
  • RM(‌Resource Manager)‌:‌资源管理器,‌代表参与分布式事务的资源,‌如数据库、‌消息队列等。‌
  • TM(‌Transaction Manager)‌:‌事务管理器,‌作为分布式事务的协调者,‌负责协调和管理工作流程。‌

        DTP模型通过XA协议和两阶段提交(‌2PC)‌协议来保证事务的ACID属性(‌原子性、‌一致性、‌隔离性、‌持久性)‌在分布式环境中得到有效维护。‌XA协议定义了全局事务管理器与局部资源管理器之间的交互接口,‌允许多个资源在同一事务中被访问,‌同时保持ACID属性的有效性。‌两阶段提交协议则确保所有资源同时提交或回滚任何特定的事务,‌从而避免数据不一致的问题。‌

        2PC,是将整个事务流程分为两个阶段,P指的是准备阶段,C指的是提交阶段。它常见的标准有XA,JTA,Seata

        由DTP模型定义事务管理器TM和资源管理器RM之间通讯的接口规范叫做XA,它规定的交互方式是这样的:应用程序AP通过TM提交和回滚事务,TM通过XA接口来通知RM数据库事务的开始,结束,提交,回滚

        2PC能保证分布式事务的原子性,但是也有很多缺陷:

        比如,在第一阶段,如果参与者迟迟不回复协调者,就会造成事务的阻塞,性能不好

        比如,在第二阶段,如果事务协调者发出提交事务指令后宕机,一部分参与者收到消息提交了事务,另一部分没有收到消息没有提交事务,这就会导致数据不一致

        再比如,在第二阶段,如果事务协调者发出提交事务指令后宕机,收到指令的参与者也宕机了,我们就不能确定事务的执行结果,究竟有没有提交

4、Seata相比传统2PC有什么区别,以及优点?

        Seata是由阿里中间件团队发起的开源项目Fescar更名而来,是一个开源的分布式事务框架,它通过对本地关系数据库的分支事务协调,来驱动完成全局事务。        

        Seata的主要优点是性能好,不会长时间占用链接资源,对业务零入侵

        与传统的2PC的区别主要两方面:

        在架构层次方面,传统的2PC方案的RM本质就是数据库自身,而Seata的RM是以jar包形式作为中间件层部署在应用程序上。

        在两阶段提交上方面,传统2PC方案是在第二阶段完成才释放资源,而Seata是在第一阶段就将本地事务提交,提高了效率。

5、Seata的TC,TM,RM的含义,以及作用?

        TC:事务协调器,它是独立的中间件,需要独立部署运行,它维护全局事务的运行状态,接收TM指令发起全局事务的提交与回滚,负责与RM通信协调各各分支事务的提交或回滚

        TM:事务管理器,TM需要嵌入应用程序中工作,它负责开启一个全局事务,并最终向TC发起全局提交或全局回滚的指令

        RM:资源管理器,控制分支事务,负责分支注册、状态汇报,并接收事务协调器TC的指令,驱动分支事务的提交和回滚

6、你知道TCC吗,它有什么样的优缺点?

        TCC是基于补偿型事务的AP系统的一种实现。补偿指的先按照事先预定的方案去执行,如果失败了就走补偿方案

        它的优点是异步执行效率高,它能对分布式事务中的各个资源分别锁定,分别提交与释放

        它的缺点是对应用的侵入性强,改动成本高,实现难度大

7、解释一下Seata的工作原理?

Seata有三个角色:

  • TM任务管理器,负责开启,提交,回滚事务的发起

  • TC事务协调器 ,接收TM的指令通知RM提交或者回滚事务

  • RM资源管理器,控制(驱动)着分支事务的提交和回滚

        假设有服务A需要调用服务B,且两个服务都需要修改各自的数据库,A服务作为程序入口充当TM和RM,B服务控制着分支事务充当RM。

  • A服务的TM向TC申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID

  • A服务的RM向TC注册分支事务,并将其纳入XID对应全局事务的管辖

  • A服务执行分支事务,写undolog日志,向TC上报事务状态

  • 当调用B服务时,B服务的RM向TC注册分支事务,该分支事务执行,然后写undolog,向TC上报事务状态

  • 服务执行完毕A服务的TM向TC发送commit或者rollback指令

  • TC接收到指令,向参与事务的RM发送指令

  • 事务参与者RM受到commit指令,删除undolog日志。 如果是rollback指令就根据undolog回滚

8、你能简单描述一下你在项目中是如何集成Seata的吗?

事务协调器:安装并启动Seata客户端

主业务端:

  • 第一步,导入Seata依赖

  • 第二步,yml中配置事务组名,同时需要添加配置文件file.conf,registry.conf,需要注意yml中事务组名与file.comf中的事务组名一致

  • 第三步,配置DataSource,需要使用Seata对DataSource进行代理

  • 第四步,数据库中添加undolog日志表

  • 第五步,业务方法上加注解@GlobalTransactional(rollbackFor = Exception.class)注解

事务参与者:

  • 前四步与主业务端相同,第五步不需要了

9、没有Seata或者TCC这些事务框架,你可以怎么处理事务?

        不用框架就要自己实现,如果业务要求强一致性这个不太好做,需要协调多个数据库的同时提交和回滚.如果是业务不要求强一致性,我可以参照TCC思想 ,可以考虑自己实现异步写数据库方案,如果失败可以做补偿.当然这个要根据业务特性来,很多大公司都是自己封装事务框架.

二、分布式锁

1、你说一下什么是分布式锁?

        分布式锁是在分布式/集群环境中解决多线程并发造成的一系列数据安全问题所用到的锁,这种锁需要被多个应用共享才可以,通常使用Redis和zookeeper来实现。

2、分布式锁有哪些解决方案?

       常用的三种方案:

        1)基于数据库实现:通常基于主键,或者唯一索引来实现分布式锁,但是性能比较差,一般不建议使用

       2) 基于Redis :可以使用setnx来加锁 ,但是需要设置锁的自动删除来防止死锁,所以要结合expire使用.为了保证setnx和expire两个命令的原子性,可以使用set命令组合。

        另外释放锁在finallly中调用del删除锁,而删除锁前需要判断该锁是否是当前线程加的锁以免误删除锁,需要通过get获取锁然后进行判断,但是需要保证get判断或和del删除锁的原子性,可以使用LUA脚本实现。

        总之自己封装Redis的分布式锁是很麻烦的,我们可以使用Redissoin来实现分布式锁,Redissoin已经封装好了。

        3)(你在项目中如何使用ZK实现分布式锁的?基于zookeeper : 使用临时顺序节点实现,线程进来都去创建临时顺序节点,第一个节点的创建线程获取到锁,后面的节点监听自己的上一个节点的删除事件,如果第一个节点被删除,释放锁第二个节点就成为第一个节点,获取到锁。

        在项目中可以使用curator,这个是Apache封装好的基于zookeeper的分布式锁方案。

3、Redis实现分布式锁可能会出现什么问题,如何解决?

https://www.cnblogs.com/haibiscuit/p/12699233.html

redis和redisson实现分布式锁的操作方法_Redis_脚本之家

        1)保证同一变量不被多个线程同时访问,使用redis命令setnx(SET if Not eXists)

        2)锁需要有超时时间,防止锁忘记释放或者宕机造成的死锁,(第一步先加锁,然后再设置超时时间,那么就不满足原子性了),为了保证setnx和expire两个命令的原子性,可以使用set命令组合set lockkey true nx ex 5

        3)虽然给锁加了超时时间,但客户端并一定能在超时时间之内完成定时任务,所以,即使当前客户端没有完成任务,此时又会有其他的客户端设置锁成功,此时同一资源将会面临多个客户端同时操作的问题.

        解决:定时任务,在锁超时之前使用lua脚本删除锁并重新设置锁和超时时间(lua具有原子性的特性,删除锁和重新加锁这两个操作要么都完成,要么都不完成)

需要用lua解决删除和判断锁的原子性,否则可能会删除掉别人的锁。

        3)Redis集群环境中,redis节点挂掉可能会导致加锁失败,可以使用Redisson的红锁来解决。

4、你项目中怎么使用分布式锁的?

https://zhuanlan.zhihu.com/p/680074340

        自己封装Redis的分布式锁是很麻烦的,我们可以使用Redissoin来实现分布式锁,Redissoin已经封装好了

5、了解Redission的看门狗原理吗?

【Redis进阶】一文搞懂Redisson的看门狗机制底层实现-CSDN博客

        Redisson对分布式锁进行了封装,对于锁超时问题,它提供了看门狗进行锁时间的续期,底层使用了定时任务每10s检查一下,如果业务还未执行完成,未释放锁,就进行超时时间续期。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值