分布式锁 redis与zookeeper

redis实现分布式锁

原理

基于redis命令setnx key value来实现分布式锁的功能,只有当key不存在时,setnx才可以设置成功并返回1,否则设置失败返回0。

方案1:
方案1存在的问题

假如在加锁成功,释放锁之前,服务器宕机了,这个锁就无法释放了,其他线程就永远无法获取到锁了。

改进之后

方案2
方案2存在的问题

获取锁和设置过期时间是2个命令,两次网络IO和redis交互,不具备原子性,可能出现获取锁成功之后 设置过期时间之前服务器宕机,导致其他线程永远都获取不到锁的现象。

方案3

1、将获取锁和设置过期时间放在lua脚本里面执行,lua脚本可以保证多个命令原子性的执行。

2、redis提供了其他命令在setnx的同时设置过期时间,分别如下所示:

  • set key value PX 多少毫秒 NX
  • set key value EX 多少秒 NX
方案3存在的问题

锁过期释放了,但是业务仍没有执行完,等到执行完业务并释放锁的时候,释放的其实是其他线程获取到的锁。

  • 线程A获取到了锁,并设置过期时间10s。
  • 当过了10秒后,线程A仍然没有执行完,但是此时线程A获取到的锁已经达到了过期时间,导致锁被释放了。
  • 此时线程B获取到了锁,并执行业务方法
  • 线程A业务方法执行完,并执行释放锁逻辑(此时释放的是线程B获取到的锁)
  • 由于锁被释放,线程C也获取到了锁,并执行业务,此时线程B、线程C都获取到了同一个锁,并执行相应的业务。
方案4
方案4存在的问题

方案4中 判断key1的value1是否等于设置的值uuid,如果是则删除,否则不执行删除逻辑,由于是2个命令,不具备原子性导致可能出现以下场景

  • 线程A成功获取锁key1,设置key1的value为uuid1,并设置过期时间10秒。
  • 线程A执行完业务逻辑,准备删除锁
  • 线程A获取到key1的value uuid1。
  • 此时线程A的锁key1刚好到了过期时间
  • cpu时间片切换,线程A停止执行,线程B开始执行
  • 线程B尝试获取分布式锁key1(由于上面线程A设置的锁已经到了过期时间,所以此处可以获取成功)
  • cpu时间片切换,线程A继续执行,由于锁的value == uuid1,所以开始删除锁(此时删除的是线程B设置的分布式锁)。导致出现了删除其他线程设置的分布式锁。
方案五
方案5存在的问题

当前仍存在锁时间达到了过期时间,但是线程没执行完的问题。

如何解决呢?

watch dog机制(Redisson底层就是基于watch dog机制来实现分布式锁的自动续期,当未设置过期时间时,会默认设置30秒,并起一个看门狗线程,每十秒去检测一次,如果当前线程仍然在执行,就自动续期,当然,如果手动设置了过期时间,就不会自动续期了)。

方案五存在的问题

redis集群的场景下,redis-master节点设置成功了,但是redis-slave节点未设置成功,如下所示:

  • 当前redis集群有三个节点,分别是redis-master、redis-slave-a、redis-slave-b
  • 线程A尝试获取分布式锁,此时在redis-master上设置key1成功。
  • redis集群采用异步主从复制,但是redis-master上设置的key内容还没有同步到slave时,redis-master节点就宕机了。
  • 此时集群重新选举,因此redis-slave-a变成了mater节点
  • 此时有线程B尝试获取分布式锁key1,由于新的master节点上没有设置key1,因此线程B设置锁成功。
  • 当前线程A和线程B就都持有了分布式锁并执行业务逻辑。
方案6

如何解决方案五仍然存在的问题呢?

使用redlock(红锁)算法,这是一个专门用于解决这种问题的分布式锁协议。

redlock:不能只在一个redis实例上加锁,应该是在多个redis实例上创建锁,当创建成功数量达到(n/2 + 1)时,才能认为加锁成功

以上方式实现复杂、性能差、运维繁琐。

我们的redis是AP高可用思想、如果要实现强一致性,应该使用CP思想的zookeeper来实现,解决主从一致性问题。

C:Consistency;一致性

A:Availabilit;可用性

P:Partition Tolerance;分区容错性

zookeeper实现分布式锁

zookeeper的节点有以下几种类型;

  • 临时节点
    当客户端和zookeeper服务端断开连接时,临时节点就会被删除
  • 临时有序节点
    临时节点且都是有序的排列
  • 持久节点
    当客户端和zookeeper服务端断开连接时,持久节点也不会被删除
  • 持久有序节点
    持久节点且都有序的排列

zookeeper实现分布式锁就是利用到了临时有序节点。

区别

相关推荐
龙哥·三年风水2 分钟前
workman服务端开发模式-应用开发-vue-element-admin封装websocket
分布式·websocket·vue
Hello.Reader1 小时前
Redis热点数据管理全解析:从MySQL同步到高效缓存的完整解决方案
redis·mysql·缓存
李昊哲小课1 小时前
deepin 安装 zookeeper
大数据·运维·zookeeper·debian·hbase
C++忠实粉丝3 小时前
Redis 介绍和安装
数据库·redis·缓存
李洋-蛟龙腾飞公司3 小时前
HarmonyOS Next 应用元服务开发-分布式数据对象迁移数据文件资产迁移
分布式·华为·harmonyos
ClouGence4 小时前
Redis 到 Redis 数据迁移同步
数据库·redis·缓存
苏三说技术4 小时前
Redis 性能优化的18招
数据库·redis·性能优化
Tttian6224 小时前
基于Pycharm与数据库的新闻管理系统(2)Redis
数据库·redis·pycharm
言之。5 小时前
redis延迟队列
redis
技术路上的苦行僧6 小时前
分布式专题(10)之ShardingSphere分库分表实战指南
分布式·shardingsphere·分库分表