- Redis 可以通过两种方式来实现分布式锁:
- 1.1 利用 Redis 提供的
SET key value NX PX milliseconds
指令,这个指令是设置一个 key-value,如果 key 已经存在,则返回 0,否则返回 1,我们基于这个返回值来判断锁的占用情况从而实现分布式锁。
- 1.2 基于 Redission 客户端来实现分布式锁,
lock()
和unlock()
方法
- a. redisson 所有指令都通过 lua 脚本执行并支持 lua 脚本原子性执行
- b. redisson 中有一个 watchdog ,它会在你获取锁之后,每隔 10 秒帮你把 key 的超时时间设为 30s,就算一直持有锁也不会出现 key 过期了。“看门狗”的逻辑保证了没有死锁发生。
- 基于 ZK 实现分布式锁的落地方案:可使用有序节点来实现
- 2.1 每个线程或进程在 Zookeeper 上的
/lock
目录下创建一个临时有序的节点表示去抢占锁,所有创建的节点会按照先后顺序生成一个带有序编号的节点。
- 2.2 线程创建节点后,获取/lock 节点下的所有子节点,判断当前线程创建的节点是否是所有的节点的序号最小的。
- 2.3 如果当前线程创建的节点是所有节点序号最小的节点,则认为获取锁成功。
- 2.4 如果当前线程创建的节点不是所有节点序号最小的节点,则对节点序号的前一个节点添加一个事件监听,当前一个被监听的节点释放锁之后,触发回调通知,从而再次去尝试抢占锁。
- 两种方案都有各自的优缺点:
- 3.1 redis的分布式锁缺点:
- 取锁的方式简单粗暴,如果获取不到锁,会不断尝试获取锁,比较消耗性能。
- Redis 是 AP 模型,在集群模式中由于数据的一致性会导致锁出现问题,即便使用Redlock 算法来实现,在某些复杂场景下,也无法保证其实现 100%的可靠性。
- 3.2 zk 分布式锁:
- zookeeper 天生设计定位就是分布式协调,强一致性。锁的模型健壮、简单易用、适合做分布式锁。
- 如果获取不到锁,只需要添加一个监听器就可以了,不用一直轮询,性能消耗较小
- 总结: 对于分布式锁而言,zookeeper应该符合 CP 模型,但是 Redis 是 AP 模型,所以在这个点上,Zookeeper会更加合适。