标签:多个 如何 哈哈 过期 red class cal argv 判断
在之前, 我也使用redis做过分布式锁, 当时的做法是这样的:
当时觉得貌似没什么问题. 是我太天真了, 今天突然想到, 恩, 有问题.
问题
1.如果在第一步之后, 程序崩了, 没有给锁设置过期时间, 导致所有后续操作都无法正常获取到锁. 怎么破?
2.在A成功上锁后, 因为IO阻塞等原因, 执行时间有点长, 锁已经过期了, 这时B过来成功上锁, A在释放锁的时候释放的就是B的锁.
3.redis突然挂了. 如果redis突然挂了, 怎么办? 当然, 可以增加redis节点, 主节点挂了, 从节点立刻补上. 但是, 主节点的数据同步到从节点也是需要时间的吧. 假设一个场景:
这个时候, 分布式锁就失效了.
那么有没有办法解决上面的问题呢? 我到万能的谷歌上找了一下, 恩, 真的有.
上面的问题一个一个解决.
问题一
如何避免没有给锁设置过期时间的问题?
其实看看就知道了, 问题出在设置key和设置value分成两条命令执行, 所以导致如果在 setnx命令执行过后, 程序崩溃, expire命令没有正常执行, 将其合并为一条命令就好啦.
set key value NX PX 5000
其中NX表示存在则不设置, PX表示过期时间.
如此, 至少可以保证不会出现没有过期时间的锁了
问题二
如何避免A释放了B的锁.
如何避免释放了其他人的锁呢? 换个问题, 如何保证这个锁是你加的呢? so easy, 加锁的时候, 讲value值设置成一个只有我知道的随机数字, 释放的时候看看值是不是我的就行了.
如此在释放的时候需要两步操作:
当然, 为了保证释放锁操作的原子性, 这两步操作最好也能合并为一步操作. 那redis如何实现值是否相同的判断呢? Lua脚本.
简单介绍一下
eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 argv1 argv2
# 看懂了吧, 哈哈
# eval 是redis内置的命令
# 第一个参数是运行的脚本逻辑
# 第二个参数表示后面有几个key
# 第五个参数开始就是附加参数, 在脚本逻辑中使用的
所以, 脚本内容如下:
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
如此, 至少可以保证不会出现A释放了B锁的情况了
问题三
如何保证在主节点挂掉的时候, 从节点接替后, 不会重复获得锁?
官网上提供了一个方法, 从多个redis实例同时获取锁. 因为我没看太明白, 之后看懂了在说吧. 过...
其实, 如果不是处理金钱这种不容出错的业务, 这种小概率事件个人觉得还是可以容忍的.
最终, 在redis单机下实现的分布式锁操作如下:
# 获取分布式锁,过期时间可调
set lock_key random_value NX PX 5000
# ...do something
# 释放分布式锁
eval "if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end" 1 lock_key random_value 标签:多个 如何 哈哈 过期 red class cal argv 判断
原文地址:https://www.cnblogs.com/hujingnb/p/12499132.html