Redis——》锁被别人释放

推荐链接:
    总结——》【Java】
    总结——》【Mysql】
    总结——》【Redis】
    总结——》【Kafka】
    总结——》【Spring】
    总结——》【SpringBoot】
    总结——》【MyBatis、MyBatis-Plus】
    总结——》【Linux】
    总结——》【MongoDB】
    总结——》【Elasticsearch】

一、锁被别人释放的场景

SET lock_key 1 EX 10 NX // 10s后自动过期

执行以上命令,给锁加自动过期时间,但每个客户端在释放锁时,都是无脑操作,并没有检查这把锁是否还归自己持有,所以就会发生释放别人锁的风险。
2a63424f0c6b4ff5840c11564a5be55e.png

  1. 客户端1加锁成功,开始操作共享资源
  2. 客户端1操作共享资源耗时太久,超过了锁的过期时间,锁失效(锁被自动释放)
  3. 客户端2加锁成功,开始操作共享资源
  4. 客户端1操作共享资源完成,在finally块中手动释放锁,但此时它释放的是客户端2的锁。

二、如何避免锁被别人释放

解决方案:客户端在加锁时,设置一个只有自己知道的唯一标识进去。
唯一标识可以采用:

  • 自己的线程ID
  • UUID(随机且唯一)

1、GET获取锁 + DEL释放锁

(1)实现

// 加锁
SET lock_key unique_value EX 10 NX

//释放锁,先判断这把锁是否归自己持有,比较unique_value是否相等,避免误释放
if redis.get("lock_key") == unique_value then
    return redis.del("lock_key")

(2)优点

解决了锁被别人释放的问题

(3)缺点

释放锁使用的是GET + DEL两条命令,这两条命令不能保证是原子操作(一起成功),有可能执行第一条GET成功,但第二条DEL却执行失败。

2、Lua脚本

因为Redis处理每个请求是单线程执行的,在执行一个Lua脚本时其它请求必须等待,直到这个Lua脚本处理完成,这样一来GET+DEL之间就不会有其他命令执行了。

(1)实现

<1>创建Lua脚本unlock.script
参数描述
KEYS[1]表示lock_key
ARGV[1]表示当前客户端的唯一标识
//Lua脚本语言
//释放锁,先判断这把锁是否归自己持有,比较unique_value是否相等,避免误释放
if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end

<2>执行Lua脚本unlock.script
redis-cli --eval unlock.script lock_key , unique_value 

(2)优点

解决了锁被别人释放的问题

三、其它

1、增大过期时间是否可以避免锁被别人释放?

如果只是一味增大过期时间,只能缓解问题降低出现问题的概率,依旧无法彻底解决问题。
原因在于客户端在拿到锁之后,在操作共享资源时,遇到的场景是很复杂的,既然是预估的时间,也只能是大致的计算,不可能覆盖所有导致耗时变长的场景。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值