Redis和Zookeeper分布式锁实现

在分布式环境中,分布式锁就是在分布式环境下用来解决多实例对数据访问一致性的一种技术方案。分布式锁的实现方式流行的主要有三种,分别是基于缓存 Redis 的实现方式,基于 ZooKeeper 临时顺序节点的实现.

分布式锁应该具备哪些特性:

  • 在分布式环境下同一时刻只能被单个线程获取;
  • 可重入,意思是已经获得锁的线程在执行的过程中不需要再次获得锁;
  • 异常或者超时自动删除,避免死锁;
  • 高性能,分布式环境下必须要性能好;

基于 Redis 实现

Redis 支持 SETNX 命令,表示设置一个 key 的值当且进度 Key 不存在的时候才能设置成功。例如执行如下命令:set ziyou 18 NX PX 10000 表示将名叫 ziyou 的 key 的值设置为 18,当且仅当不存在名为 ziyou 的 key 的时候才能设置成功,并且过期时间设置为 10 秒钟。

一开始redis作为分布式锁用的是setnx,再这基础上设置个定时过期时间,但这种方式有什么问题呢?

从2.6.12版本开始,redis为SET命令增加了一系列选项(set [key] NX/XX EX/PX [expiration]):

  • EX seconds – 设置键key的过期时间,单位时秒
  • PX milliseconds – 设置键key的过期时间,单位时毫秒
  • NX – 只有键key不存在的时候才会设置key的值
  • XX – 只有键key存在的时候才会设置key的值

再然后是释放锁的时机该如何定?

  • 不管我们定多少过期时间,都不能保证,在这段时间内锁住的代码执行完成了,所以这个时间定多少都不好;
  • 如果不定时间,当执行完成后释放锁,问题就是如果执行到一半机器宕机,那这把锁就永远放不掉了

优点

  • 实现简单,理解逻辑简单;
  • 性能好,毕竟是缓存。

缺点

  • Redis 容易单点故障,集群部署;
  • key 的过期时间设置多少不明确,只能根据实际情况调整。

基于Zookeeper实现

对于 ZK 来说,实现分布式锁的核心是临时顺序节点。

  • 使用子节点,每个线程获取锁时,都在固定节点下创建临时顺序的子节点,默认最小节点线程获得锁,当释放锁时,删除对应的子节点即可,如果线程出现意外,失去zk连接之后,相对应的子节点也会自动清除

优点

  • ZK 本身就是集群部署,避免单机故障;
  • 顺序节点所以不用考虑过期时间设置问题;

缺点

  • 实现较为复杂;
  • 非缓存机制,大量频繁创建删除节点会影响 ZK 集群性能;
有用就打赏一下作者吧!