redis---分布式锁存在的问题及解决方案(Redisson)

文章目录

1.setNx

初识分布式锁大多数人都是从setNx命令开始的,我们很轻易的就可以借助setNx命令及redis的特性创建一个简陋的分布式锁。释放锁时只需要直接删除即可。

存在问题:

  • 客户端所在节点崩溃,无法正确释放锁
  • 业务逻辑异常,无法执行 DEL指令
  • 如何保证锁不被别的应用程序释放

上述只是列出的一小部分问题,实际还存在很多漏洞没有展示出来。我们循序渐进一点一点啃先解决以上几个问题。

2.set NX NP

对于出现异常锁无法释放问题,我们很容易可以想到能够通过设置一个过期时间来进行处理。比如像订单30分钟未支付默认放弃此订单这样。这里采用常规的SETNX + EXPIRE 为两个单独的命令会缺乏原子性,想象一下如果加锁成功但是客户端节点在执行EXPIRE 命令时突然宕机了。这种情况锁将会无法主动释放。

结局方案:
好在redis自2.6.X 之后,官方拓展了 SET 命令的参数,满足了当 key 不存在则设置 value,同时设置超时时间的语义,并且满足原子性。

SET resource_name random_value NX PX 10000
  • NX:表示只有 resource_name 不存在的时候才能 SET 成功,从而保证只有一个客户端可以获得锁;
  • PX 10000:表示这个锁有一个 10 秒自动过期时间。

此时虽然初步解决了锁无法释放的问题,但是又打开新的缺口。比如我们将时间设为了500ms,但是此时突然网络抖动程序执行时间被大大延长我们执行了2s才结束。但是,锁已经被提前释放了。这样就又会产生新的冲突。

3.如何保障自己的锁只能自己来释放?

假如有以下情景:

客户 1 获取锁成功并设置设置 30 秒超时;
客户 1 因为一些原因导致执行很慢(网络问题、发生 FullGC……),过了 30 秒依然没执行完,但是锁过期「自动释放了」;
客户 2 申请加锁成功;
客户 1 执行完成,执行 DEL 释放锁指令,这个时候就把客户 2 的锁给释放了。

最直观能想到的方案就是:在执行 DEL 指令的时候,我们要想办法检查下这个锁是不是自己加的锁再执行删除指令。

我们必须保证A上的锁只有A能解锁,如果任何人都可以随意解锁那么锁的存在就没有任何意义。我们在设置锁时可以为每个锁打上一个独属于自己的标签。就像车牌号一样,可以帮我们快速的分辨是不是自己的车。否则你拿钥匙怼一百遍也是徒劳的。
在这里插入图片描述
假设伪代码如下:

// 比对 value 与 唯一标识
if (redis.get("lock:9999999").equals(random_value)){
   redis.del("lock:99999999"); //比对成功则删除
 }

我们可以直观的看到通过常规命令的方式,每一条指令都是独立的又会存在原子性问题。这个问题我们先不考虑,看看redisson是如何实现的:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值