[001-03-007].第26节:分布式锁迭代3->优化基于setnx命令实现的分布式锁-防锁的误删

我的博客大纲

我的后端学习大纲


1、问题分析:

1.1.问题:

  • 1.锁的超时释放,可能会释放其他服务器的锁

1.2.场景:

  • 1.如果业务逻辑的执行时间是7s。执行流程如下
    • 1.index1业务逻辑没执行完,3秒后锁被自动释放。
    • 2.index2获取到锁,执行业务逻辑,3秒后锁被自动释放。
    • 3.index3获取到锁,执行业务逻辑
    • 4.index1业务逻辑执行完成,开始调用del释放锁,这时释放的是index3的锁,导致index3的业务只执行1s就被别人释放。最终等于没锁的情况

1.3.解决方式:

  • 1.setnx获取锁时,设置指定一个的唯一值(例如:uuid);释放前获取这个值,判断是否自己的锁
    在这里插入图片描述

1.4.编码实现:

在这里插入图片描述


2.新问题改善:

2.1.新问题说明:

  • 1.上述改善后,出现的新问题就是判断与删除条件不再一个命令中,操作缺乏原子性
    在这里插入图片描述

2.2.场景:

  • 1.index1执行删除时,查询到的lock值确实和uuid相等
  • 2.index1执行删除前,lock刚好过期时间已到,被redis自动释放
  • 3.index2获取了lock
  • 4.index1执行删除,此时会把index2的lock删除

2.3.解决方案:

  • 在redis中没有一个命令可以同时做到判断 + 删除,所有只能通过其他方式实现(如LUA脚本实现)

2.4.LUA脚本解决:

  • 1.删除LUA脚本:
if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end
  • 2.代码实现:
public void deduct() {
    String uuid = UUID.randomUUID().toString();
    // 加锁setnx
    while (!this.redisTemplate.opsForValue().setIfAbsent("lock", uuid, 3, TimeUnit.SECONDS)) {
        // 重试:循环
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    try {
        // this.redisTemplate.expire("lock", 3, TimeUnit.SECONDS);
        // 1. 查询库存信息
        String stock = redisTemplate.opsForValue().get("stock").toString();

        // 2. 判断库存是否充足
        if (stock != null && stock.length() != 0) {
            Integer st = Integer.valueOf(stock);
            if (st > 0) {
                // 3.扣减库存
                redisTemplate.opsForValue().set("stock", String.valueOf(--st));
            }
        }
    } finally {
        // 先判断是否自己的锁,再解锁
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] " +
            "then " +
            "   return redis.call('del', KEYS[1]) " +
            "else " +
            "   return 0 " +
            "end";
        this.redisTemplate.execute(new DefaultRedisScript<>(script, Boolean.class), Arrays.asList("lock"), uuid);
    }
}

2.5.压力测试:

在这里插入图片描述


  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值