你不知道的分布式锁+分布式事务面试题

261 阅读7分钟

分布式锁+分布式事务面试题

什么是分布式锁?

 在分布式系统之间,保证某些系统资源同步访问的一种方式。
 
 如: 减库存的接口  多应用访问时都要对库存数据做操作,可能会造成超卖问题
 可以通过分布式锁解决。

分布式锁的使用场景?

库存操作
积分操作
钱包操作

能否基于JDK提供的锁实现分布式锁?

JVM锁无法解决: 因为对应的服务会做集群

分布式锁有哪些实现方式?

基于数据库实现

可以通过数据库的悲观锁 (行锁)实现,
在查询库存数量用于修改时,在select语句后加上 for update

其它客户端访问时,如果当前库存有客户端在操作,会产生阻塞。性能低

基于Redis实现

基于Redis的单线程模型, 不同的客户端并发操作数据时 通过redis 的setnx方案尝试谁能在redis中存储数据,能存储代表获取到锁, 当操作完毕后再删除掉对应的key

setnx key value   存在:0      不存在: 设置成功 并返回1

Redission框架实现了 基于Redis的高可用分布式锁RLock

基于zookeeper实现

基于zookeeper的文件系统和watch监听机制实现分布式锁, 大概实现思路: 多个客户端要操作资源时,在指定目录节点下 创建临时节点, 节点序号最小的算占有锁,当执行完毕后删除对应节点,下一个最小的节点占有锁。

分布式锁实现方案对比总结?

基于数据库实现,最简单,性能不好,并发量少时可用

基于Redis的Redission方案是主推方案,实现了公平锁、可重入锁、支持redis集群、锁的自动续约,

通过简单的配置 ,获取RLock对象,  调用对象.lock()加锁  调用.unlock方法解锁即可
代码侵占非常低


我们项目中使用的是Redission, 不过在redis master节点宕机后,有多个客户端获取到同一个锁的风险。


基于zookeeper性能对比redis稍慢一些,强一致性的zk 在leader宕机后会出现短时间的不可用。

Redission实现分布式锁RLock的原理?

加锁(lock)
	1. 每一个竞争锁的客户端都会有一个唯一编号(UUID:线程ID)
	2. 加锁使用lua脚本,保证多个命令的原子性
		脚本中考虑到了客户端的互斥
		考虑到相同客户端的重入锁
		// 锁的格式  
		      锁名      客户端ID                         重入锁次数
        hset myLock 8743c9c0-0795-4907-87fd-6c719a6b4586:1 1
锁的自动续约
	加锁后会启动一个watchdog看门狗,是一个后台线程,会每隔10秒检查一下,如果客户端存活且还持有锁key,会续约锁的超时时间

解锁(unlock)
	也是使用lua脚本 进行解锁
		脚本先判断是否有 hexist 锁名称 客户端ID 对应的信息 
			不包含: 代表没有获得对应的锁,返回锁的失效时间
			
			如果包含: 会对value部分减1 ,在判断结果是否大于0
			         大于0代表这个重入锁还没有完全解开
			          
			         如果不大于0 则删除锁 del key

ZK如何实现分布式锁简述?

方案一: 创建临时节点实现分布式锁
	客户端尝试创建指定文件节点,创建成功占有锁,没创建成功监听文件节点变化,如果文件节点删除 再次尝试 创建指定文件节点 . 成功占有锁后,如果执行完毕代码 删除掉对应文件节点代表释放锁。  这种方式会存在惊群效应,当多个客户端等待锁释放时,如果锁释放多个客户端会同时尝试创建文件节点,给zk带来很大并发压力,性能不好
	
方案二: 创建临时顺序节点实现分布式锁
	客户端尝试在指定文件节点目录下,创建临时有序文件节点, 每个节点都有编号,当前编号最小的文件节点 为获取到锁,执行代码。  每个等待锁的客户端 都监听它上一个节点的变化。 如果上一个节点被删除了 当前节点编号 变为最小  相当于获取到锁

什么是事务及事务的特性?

事务 指的是一系列的操作,要么全部成功,要么全部失败。
在数据库中,指的是一个操作由一些列SQL组成,这些SQL看成一个整体,要么全部成功,要么全部失败。

数据库中的事务满足ACID的特性
原子性(Atomicity)
一致性(Consistency)
隔离性(Isolation) 
持久性(Durability)

什么是分布式事务?

在分布式架构中,一个操作可能横跨多个微服务,多个数据库,传统的本地事务无法解决,需要使用分布式事务来解决。

什么是CAP定理?

在分布式系统中,
C: 指的是多个系统中数据的一致性。
A: 指的是服务的高可用
P: 指的是分区容错

即使网络故障的时候能够做到分区容错,在服务出现瘫痪时也能保证对应服务的高可用,而且整个系统的数据保持一致性。想完全满足以上3点是不可能的,所以业界主要选择32 优先保证两点,但分区容错和网络有关无法避免,所以P必须要保证 常见的两种方案:
CP: 保证一致性,分区容错
AP:保证高可用,分区容错

什么是Base定理?

Base定理,对CAP的平衡落地理论。
强调的是: 
   保证基本可用(核心服务高可用)
   允许存在软状态(运行出现一段时间的数据不一致情况)
   最终一致性(最终能够达到数据的一致性)

zk和eureka的区别?(从CAP的角度分析)

zk: cp   强调一致性

eureka: ap  强调高可用

分布式事务的解决方案?

刚性事务解决方案 (CP)
	基于XA的二阶段提交 (Seata)
	
	Seata AT (模式)   1. 预提交操作 真正提交 (提交的同时创建回滚日志) 
	                 2. 如果1阶段全部提交成功 删除回顾日志
	                    如果1阶段有一个失败 会利用回滚日志 进行数据补偿(异步)
                        
                     
                     数据库必须支持事务
                     JDBC 
柔性事务解决方案 (Base)
	TCC (补偿型) (Seata)   try 尝试执行  confirm 确认操作    cancel 取消 
	               
	SAGA (补偿型) (Seata)  
	
	MQ事务消息 (异步通知)  RocketMQ
	
	MQ+本地消息表 (异步通知)   创建订单      -->      减库存 
	                        回馈确认 

seata介绍

阿里推出的一款开源的、一站式的分布式事务解决方案。 提供了TCC、SAGA、AT等模式的解决方案,XA二阶段模式也即将推出,适合各类微服务场景。在2019年1月左右开始推出最初版本,目前已经更新到1.2.1版本,由阿里的团队积极维护,而且社区非常活跃,是目前非常火的分布式事务解决方案

我们项目中分布式事务是如何处理的?

可以说使用seata框架, 不过最好在0.9以前版本 2019.10.16日发布0.9版本


MQ+本地消息表的方式在过去使用的最多,因为可靠消息队列的异步通信效率很高。
不过需要针对特定的场景要做对应的设计,当子事务比较多时,或者要考虑各种补偿方案时实现比较复杂。