Redis实现分布式锁的种种细节
1、redis分布式锁直接使用 setNx
获取锁🔒,del key
释放锁
会造成 「 死锁 」的问题,获取锁的线程没有释放锁,进程死掉了,其他进程永远无法获取锁
2、给锁对应的key添加过期时间不就可以解决死锁的问题了吗?
127.0.0.1:6379> SETNX lock 1 // 加锁(integer)
127.0.0.1:6379> EXPIRE lock 10 // 10s后自动过期(integer)
上面两个命令有什么问题吗?
不是原子操作,可能 expire
没有执行!使用如下复合命令 👇
127.0.0.1:6379> SET lock 1 EX 10 NX
3、这样还会存在一个问题,进程2释放的是进程1的锁
进程1操作时间太久,还没有主动释放锁,锁就过期了,然后进程2获取锁,然后执行,进程2还没有执行完成,进程1执行完了,释放
锁,但是释放的是进程2的锁。「 释放他人锁」和 「 锁过期时间问题」
- 加锁:
SET lock_key $unique_id EX $expire_time NX
- 操作共享资源
- 释放锁:Lua 脚本,先 GET 判断锁是否归属自己,再 DEL 释放锁
1 | // 判断锁是自己的,才释放 |
4、锁过期时间不好评估怎么办?
假设一个方案:
加锁时,先设置一个过期时间,然后我们开启一个「守护线程」,定时去检测这个锁的失效时间,如果锁快要过期了,操作共享资源还未完成,那么就自动对锁进行「续期」,重新设置过期时间。
如果你是 Java 技术栈,幸运的是,已经有一个库把这些工作都封装好了:Redisson。
Redisson 是一个 Java 语言实现的 Redis SDK 客户端,在使用分布式锁时,它就采用了「自动续期」的方案来避免锁过期,这个守护线程我们一般也把它叫做「看门狗」线程。
以上都是基于单机redis的角度思考的redis分布式锁的问题,主要有三点 👇
1、死锁问题 (加过期时间解决)
2、释放他人锁 (添加线程标志)
3、锁过期时间问题 (守护线程自动续期)
如果是redis集群模式下会有哪些问题呢 👇
在redis主从模式下,如果master节点突然宕机了,锁还没有同步到从节点是,是不是分布式锁就丢了???
Redis 作者提出的 Redlock 方案,是如何解决主从切换后,锁失效问题的。如何解决这个问题呢 ? 「 **RedLock**」
Redlock 的方案基于 2 个前提:
- 不再需要部署从库和哨兵实例,只部署主库
- 但主库要部署多个,官方推荐至少 5 个实例
也就是说,想用使用 Redlock,你至少要部署 5 个 Redis 实例,而且都是主库,它们之间没有任何关系,都是一个个孤立的实例。
注意:不是部署 Redis Cluster,就是部署 5 个简单的 Redis 实例。