SpringCloud面试题
# 实现分布式锁的解决方案中,你认为Zookeeper和Redis哪种更好
分布式锁主要用于解决多进程/线程并发访问共享资源时的安全性问题,可以分为两类:
- 共享锁:允许多个进程同时访问某个共享资源,适用于幂等性场景,避免重复加锁所带来的一个性能开销
- 排他锁:同一时刻只允许一个进程访问资源,适用于非幂等性场景
实现分布式锁最常用的中间件有Redis和Zookeeper
基于Redis实现的分布式锁
Redis可以通过两种方式来实现
- 基于Redis提供的setnx指令,这个指令在设置key时,如果这个key已经存在,会返回一个零,表示当前无法设置,所以可以用key表示锁,设置key成功表示获得锁,设置失败表示锁被其他线程获得
- 使用Redisson客户端提供的分布锁,Redisson提供了分布式锁的封装方法,我们只需要调用里面封装好的API,lock和unlock方法,就可以去实现锁的抢占和释放,
- 而且Redisson里面所有的指令,都是通过lua脚本去实现的,可以保证执行所有指令的原子性,
- 另外Redisson里提供了watch dog,看门狗,他会在你获取锁之后啊,每隔十秒钟去给锁做一个续约,从而避免锁的过期,
基于Zookeeper实现的分布式锁
Zookeeper可以使用有序节点来实现,每个线程或者进程会在Zookeeper上的lock目录下,去创建一个临时有序节点,表示抢占锁,所有创建的节点,都会按照先后顺序,生成一个带有有序编号的节点,线程创建节点后,获取lock节点下的所有子节点,去判断当前线程创建的节点,是否是所有子节点里面序号最小的,如果当前线程创建的节点,是所有子节点中最小的节点,那么我们认为他是获得锁成功, 如果当前线程创建的节点不是最小的,那么就对当前线程的前一个节点建立事件监听,当监听到前一个节点被释放后,会触发一个回调,告诉当前线程,去再次尝试抢占锁,这就是Zookeeper基于有序节点实现分布锁的实现原理
我认为这两种方案都有它各自的优缺点,
- 对于Redis,
- 在获得锁时,非常简单粗暴,如果取不到锁,就会不断去尝试,这会对整个应用程序的性能,会造成很大的影响,
- Redis是一个AP模型,也就是可用性模型,在集群模式中,很容易存在数据一致性问题,导致锁出现问题,即便是我们去使用red lock红锁,这种算法来去实现分布锁,但是在某些复杂的场景下,也无法去保证锁得百分之百可用,
不过呢在实际开发中啊,我们就使用Redis来实现分布锁还是比较常见的,因为大部分的情况下,都不会遇到一些极端复杂的一些场景,更重要一点是Redis性能是比较高的,所以在高并发场景中啊,它会比较合适一些, 对于Zookeeper来说,Zookeeper天生的设计定位,就是一个分布式协调组件,它是一个CP模型,所以它更适合用来去实现分布式锁, 他如果获取不到锁呢,只需要添加一个监听器就行,不用一直去轮询,所以性能消耗会比较小,如果在两者之间一定要做选择的话,就我来说比较推崇Zookeeper来实现分布锁,因为对于分布锁来说,它是一个CP模型的场景,而Redis是一个AP模型的场景,所以Zookeeper更加适合一点
上次更新: 2025/6/10 17:21:17