微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

分布式锁原理和使用

分布式锁基本原理

image-20211005222836043

redis 中有一个 SETNX 命令,该命令会向 redis 中保存一条数据,如果不存在则保存成功,存在则返回失败。

我们约定保存成功即为加锁成功,之后加锁成功的线程才能执行真正的业务操作

分布式锁演进一

核心代码

    public Map<String, List<Catalogs2Vo>>  getcatalogJsonFromDBWithRedisLock() {
        //1. 占分布式锁
        Boolean lock = redistemplate.opsForValue().setIfAbsent("lock", "111");
        if(lock){
            //加锁成功 执行业务
            Map<String, List<Catalogs2Vo>> dataFromDb = getDataFromDb();
            //得到锁之后释放 删除锁
            redistemplate.delete("lock");
            return  dataFromDb;
        }
        else{
            //加锁失败 再次请求 休眠100ms重试
            getcatalogJsonFromDBWithRedisLock();
        }
        return getDataFromDb();
    }

问题:setnx占好了位,业务代码异常或者程序在页面过程中宕机。没有执行删除锁逻辑,这就造成了死锁

解决: 设置锁的自动过期,即使没有删除,会自动删除

分布式锁演进二

按照之前的弊端添加了过期时间,自动删除

image-20211005223650660

问题:setnx设置好,正要去设置过期时间,宕机。又死锁了

解决: 设置过期时间和占位必须是原子的。redis支持使用setnx ex命令

分布式锁演进三

原子命令:设置过期时间和锁

set lock 1111 EX 300 NX

image-20211005224209249

问题:如果由于业务时间很长,锁自己过期了,其他线程又进来创建锁执行业务代码,我们直接删除,有可能把别人正在持有的锁删除

解决: 占锁的时候,值指定为uuid,每个人匹配是自己的锁才删除

分布式锁演进四

设置uuid保证自己不能删除别人的锁

image-20211005225001762

问题: 如果正好判断是当前值,正要删除锁的时候返回值的时候,锁已经过期,别人已经设置到了新的值。那么我们删除的是别人的锁

解决删除锁必须保证原子性。使用redis+Lua脚本完成

分布式锁最终版

image-20211005230417251

保证加锁【占位+过期时间】和删除锁【判断+删除】的原子性。更难的事情,锁的自动续期

压测访问

image-20211005235512395

只有一个服务从数据库拿到了数据

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐