Loading

分布式锁原理和使用

分布式锁基本原理

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

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

posted @ 2021-10-12 16:55  炒焖煎糖板栗  阅读(131)  评论(0编辑  收藏  举报