当前位置: 首页 > news >正文

分布式锁 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实现分布式锁

区别


http://www.mrgr.cn/news/9697.html

相关文章:

  • 幂等性简介
  • 基于x86 平台移植ffmpeg3.4.5及ffmpeg验证
  • 汽车租赁|基于SprinBoot+vue的汽车租赁系统(源码+数据库+文档)
  • SpringBoot的内置缓存以及整合第三方缓存
  • 【25届秋招】Shopee 0825算法岗笔试
  • Long Short-Term Memory
  • JavaScript性能对决:左移运算符VS乘法运算,谁更胜一筹?
  • 自动驾驶-机器人-slam-定位面经和面试知识系列10之高频面试题(04)
  • Facebook的AI助手:如何提升用户社交体验的智能化
  • Linux系统下的容器安全:深入解析与最佳实践
  • ThinkPHP6异步请求的全面解析
  • Linux文件IO缓存
  • Web API 学习笔记 第四弹
  • JavaScript学习文档(5):为什么需要函数、函数使用、函数传参、函数返回值、作用域、匿名函数、逻辑中断
  • SQLite使用datetime函数
  • 集合及数据结构第七节————LinkedList的模拟实现与使用
  • Redis下载安装使用教程图文教程(超详细)
  • 海莲花活跃木马KSRAT加密通信分析
  • 本题目要求计算分段函数的值:
  • 能源与节能