SpringCloud面试题
# 实现分布式锁的解决方案中,你认为Zookeeper和Redis哪种更好
第一个,我们为什么要使用分封锁,使用分布式锁的一个核心目的,是为了去解决在同一个时刻,有多个进程或者多个线程去访问某个共享资源,所带来的一个安全性问题,而根据锁的一个用途呢,我们可以把它分为两类,第一类是属于共享锁,所谓的共享所,就是说我们在同一个时刻,允许多个进程或者线程去访问某个共享资源,这样一个核心点是可以,适用在幂等性的一个场景中,从而去避免重复加锁所带来的一个性能开销,第二个类是叫排他锁,排他锁,就是说我在同一个时刻,只允许一个线程或者竞争去访问这个共享资源,这个呢比较适合在非幂等性场景中,也就是说我们需要去保证在同一个时刻,只有一个竞争或者线程去访问这个共享资源,目前啊去实现分布式锁,最常用的中间件呢有REDIS和主keeper,REDIS呢可以通过两种方式来实现,第一种是基于REDIS本身提供的,叫set nx这样一个指令,这个指令有一个特殊的点,就是我们往里面去设置一个key的时候,如果发现这个key已经存在于REDIS的服务器上,它会返回一个零,表示我当前无法设置,否则的话返回个一表示设置成功,那么我们的程序可以根据零和一,来判断当前的这样一个状态,从而去表示获得锁,第二个啊,基于REDITION这样一个客户端来实现分布锁,REDITION呢提供了分布式锁的一个封装方法,我们只需要调用里面封装好的API,lock和unlock方法,就可以去实现所的抢占和释放,而REDITION里面所有的指令,都是通过弱脚本去实现的,而弱脚本呢,它可以保证我们执行所有指令的一个原子性,另外呢REDITION里面提供了一个叫watch dog,翻译过来就是看门狗,他会在你获取锁之后啊,每隔十秒钟去帮你把你的key的时间做一个续约,从而去避免你的锁的过期,第二种呢是基于JUKEEPER来实现分布式锁,关于JUKEEPER这样一个概念的讲解呢,大家可以看我前面几天上传的一个视频,JUKEEPER去实现分布式锁的方法呀比较多,我们可以使用有序节点来实现,大家可以看这个图,每个县城或者进城都到JUKEEPER上的lock目录下,去创建一个临时有序节点,去表示抢占,所,所有创建的节点,都会按照先后顺序,生成一个带有有序编号的节点,线程创建节点之后啊,获取洛克节点下的所有子节点,去判断当前线程创建的节点,是否是所有子节点里面序号最小的,如果当前线程创建的节点,是所有子节点中最小的节点,那么我们认为他是获得所成功,如果当前线程创建的节点不是最小的,那么我们需要去对当前线程的前一个节点,去建立一个事件监听,当被监听的这个节点被释放之后,则触发一个回调,告诉当前线程,从而再一次去尝试抢占所,这就是JUKEEPER,基于有序节点实现分布锁的一个实现原理,我认为呢这两种方案都有它各自的优缺点,对于REDIS来说啊,它有以下这样一些缺点,第一个呢他在获得锁的时候呢,它非常简单粗暴,如果取不到锁,他就会不断去尝试,这个会对我的整个应用程序的一个性能,会造成很大的影响,第二个release它是一个AP模型,也就是我的一个可用性模型,那么在集群模式中呢,很容易存在数据一致性,会导致锁出现问题,即便是我们去使用red lock,这种算法来去实现分布锁,但是在某些复杂的场景下,也无法去保证锁得百分之百可用,不过呢在实际开发中啊,我们就使用REDIS来实现分布锁还是比较常见的,因为大部分的情况下,都不会遇到一些极端复杂的一些场景,更重要一点是read性能是比较高的,所以在高并发场景中啊,它会比较合适一些,对于租cube来说,租cube天生的设计定位,就是一个分布式协调组件,它是一个CP模型,所以它更适合用来去实现分布式锁,对于TOKYO来说,他如果获取不到锁呢,只需要添加一个监听器就行,不用一直去轮询,所以性能消耗会比较小,如果在两者之间一定要做选择的话,就我来说比较推崇DK来实现分布锁,因为对于分布锁来说,它是一个CP模型的场景,而REDIS是一个AP模型的场景,所以做keeper呢更加适合一点