分布式锁 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实现分布式锁就是利用到了临时有序节点。

区别

相关推荐
大鹏说大话10 分钟前
分布式事务怎么选型?2PC、TCC、SAGA、本地消息表一次讲清
分布式
用户094248568031 小时前
第1章:Redis 术语全景与单线程工作原理
redis·快应用·源码阅读
Eloudy2 小时前
ASTRA-sim 3.0:通过高保真GPU和基础设施建模进行下一级分布式机器学习模拟
人工智能·分布式·机器学习
hflmwl82 小时前
RedisDesktopManager安装包中文版官方下载,redis可视化客户端工具下载
数据库·redis·缓存·可视化客户端工具
泡海椒2 小时前
JQuick-SQL 模块架构:从 SQL AST 到分布式执行
分布式·sql·架构
用户84913717547163 小时前
订单超时未支付自动取消实现方案 | 三种方案详解
redis·面试·rabbitmq
easyboot3 小时前
Memurai Windows下的redis
redis
starzy19903 小时前
深度拆解 Kafka 源码:Producer 构造器装配了哪些核心组件
分布式·kafka
我不会起名字3224 小时前
Redis RDB 落盘时的 fork 停顿:COW 机制与 3 个降低影响的配置
redis·持久化·fork·cow·rdb
程序员大阳4 小时前
副队长大数据教程(7)--Hadoop 集群角色配置逻辑详解
大数据·hadoop·分布式·集群·配置·角色·逻辑