Redis实践-分布式锁

概述

通过redis实现分布式锁是一种比较常见的方式,分布式锁一般使用的是setnx(set if not exist)指令,只允许被一个客户端占用,用完后调用del指令释放。

问题一

如果在执行逻辑的过程中,服务器崩溃,或者发生了未知的异常,可能会导致del指令无法被执行,这样会陷入死锁。

解决方法

我们在拿到锁的时候,再给锁加上一个过期时间(expire 指令),在保证出现异常的时候自动释放。

问题二

如果在setnx 和 expire指令之间进程挂掉了,会导致expire得不到执行,造成死锁,

解决方法

需要setnx和expire这两条指令一起执行,由于expire依赖于setnx的执行结果,如果setnx没有抢到锁,expire是不能执行的,所以不能用redis的事务来解决。
最终这个问题在redis2.8版本得到解决,作者在set指令中加了扩展参数,使setnx和expire指令一起执行。

超时问题

如果在加锁和释放锁的之间的逻辑执行太长,超出了锁的超时限制,因为锁过期了,第二个线程持有这把锁,之后第一个线程执行完业务,把锁释放了。

解决方法

在set指令的value值设置一个随机数,释放锁时先匹配随机数是否一致,然后在删除key,匹配value和删除key不是一个原子操作,可以使用lua脚本来保证原子性,

 if redis.call("get",KEYS[1]) == ARGV[1] then
  return redis.call("del",KEYS[1])
else
return 0
end

redis的锁续期

可以通过redission来实现分布式锁,利用redisson的watchdog机制,定时给重置锁的超时时间,流程如下:


image.png

依赖的jar包

        
            org.redisson
            redisson
            3.12.4
        

调用方法

    public static void main(String[] args) {
        RedissonClient redisson = Redisson.create();
        RLock lock = redisson.getLock("lock");
        lock.lock(1, TimeUnit.MINUTES);
    }

在调用RLock 的lock方法时,可通过leaseTime属性设置锁持有的最大时间,如果超过这个设置的最大时间,会释放锁。

你可能感兴趣的:(Redis实践-分布式锁)