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包

        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.12.4</version>
        </dependency>

调用方法

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

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

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容