Redis分布式锁

Redis分布式锁

基于单Redis节点的分布式锁

标准实现方式

  1. 获取锁
SET resource_name my_random_value NX PX 30000
  1. 释放锁,通过lua脚本释放,保证原子性
// 必须判断是自己加的锁,即随机数是自己产生的,不然就有可能把别人的锁给释放了
if redis.call("get",KEYS[1]) == ARGV[1] then 
    return redis.call("del",KEYS[1])
else
    return 0
end

几个关键问题

  • 过期时间的设置,防止获取锁的客户端因各种原因无法释放锁时,其他客户端无法获取锁问题
  • 获取锁的原子操作,不可以分成多步实现,这样就是原子操作了
  • 随机字符串my_random_value 是必要的,它保证了一个客户端释放的锁必须是自己持有的那个锁
# 如果my_random_value是个固定值,可能出现的问题
客户端1获取锁成功。
客户端1在某个操作上阻塞了很长时间。
过期时间到了,锁自动释放了。
客户端2获取到了对应同一个资源的锁。
客户端1从阻塞中恢复过来,释放掉了客户端2持有的锁。
  • 释放锁必须用Lua脚本来实现,可以保证“GET”,判断,“DEL” 三步操作的原子性
# 不用lua脚本可能出现的问题
客户端1获取锁成功。
客户端1访问共享资源。
客户端1为了释放锁,先执行’GET’操作获取随机字符串的值。
客户端1判断随机字符串的值,与预期的值相等。
客户端1由于某个原因阻塞住了很长时间。
过期时间到了,锁自动释放了。
客户端2获取到了对应同一个资源的锁。
客户端1从阻塞中恢复过来,执行DEL操纵,释放掉了客户端2持有的锁。
  • 如果Redis宕机了怎么办?所有客户端都无法获得锁。为了提高可用性,Redis节点可以挂个Slave,Master节点不可用时,Slave自动升级成Master,但由于Redis的主从复制是异步的,锁就可能出问题
客户端1从Master获取了锁。
Master宕机了,存储锁的key还没有来得及同步到Slave上。
Slave升级为Master。
客户端2从新的Master获取到了对应同一个资源的锁。

RedLock

RedLock 就是为了解决上述最后一个问题,当有多个Redis节点,如何保证锁的安全性。

获取锁的过程
  1. 获取当前时间戳
  2. 按照顺序依次向N个Redis节点执行获取锁操作,这个操作跟上述单节点的获取锁一样。另外,为了防止节点不可用的情况出现,这个操作还设置了个超时时间(远小于锁的有效时间)。
  3. 计算整个获取锁的过程总消耗时长,如果客户端从大多数节点成功获取到锁(>= N/2 + 1),且获取锁消耗时间没有超过锁的有效时间,那么获取锁成功,否则,获取失败。
  4. 如果最终获取锁成功,那么这个锁的有效时间等于最初的锁的有效时间 - 整个获取锁过程耗时。
  5. 如果最终获取锁失败,则客户端应立即向所有节点发起释放锁的操作。(有可能节点接收到了获取锁请求,但是返回成功消息失败,客户端误认为没有获取到,所以每次都要向所有节点发起释放锁操作)
释放锁的过程

客户端向所有节点发起释放锁的操作

问题
  • 锁数据还没持久化,就崩溃重启,导致锁丢失,可能会导致多客户端同时获得锁。

延迟重启,一个节点崩溃后,先不立即重启它,而是等待一段时间再重启,这段时间应该大于锁的有效时间,这样重启前,所有参与的锁都会过期,

  • 如果客户端长期阻塞导致锁过期,那么阻塞完之后,访问共享资源就不安全了。

记录当前锁的随机字符串是否是该客户端产生的,如果是,则继续操作,如果不是,则放弃访问资源。(这种方法也有问题)

分布式锁使用的两个方向

  • 为了效率(efficiency),协调各个客户端避免做重复的工作。即使锁偶尔失效了,只是可能把某些操作多做一遍而已,不会产生其它的不良后果。

  • 为了正确性(correctness)。在任何情况下都不允许锁失效的情况发生,因为一旦发生,就可能意味着数据不一致(inconsistency),数据丢失,文件损坏,或者其它严重的问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值