Redis学习之五---高并发分布式锁实战

在学习Redis使用分布式锁的时候,我们必然会遇到实际开发中的一些问题。进行了一些记录

一:缓存穿透

缓存穿透是指查询一个根本不存在的数据,缓存层和存储层都不会命中,通常出于容错的考虑,如果从存储层查不到数据就不写入缓存层。
缓存穿透将导致不存在的数据每次请求都要到存储层去查询, 失去了缓存保护后端存储的意义。
解决方案如下:缓存一个空对象

 public String  getCacheThrough(String key){
        String cacheValue = (String) redisTemplate.opsForValue().get(key);
        if(null == cacheValue){
            // 从数据库中获取
            String  dbValue =  getDbValue(key);
            redisTemplate.opsForValue().set(key,dbValue);
            // 如果数据库都没有,就设置一个key过期时间为300秒的
            if(dbValue == null){
                redisTemplate.expire(key,60 * 5, TimeUnit.SECONDS);
            }
            return  dbValue;
        }
        return cacheValue;
    }

另一种解决方式就是:
布隆过滤器
对于不存在的数据布隆过滤器一般进行过滤,不让请求往数据库发送,由布隆过滤器进行第一层过滤。
向布隆过滤器中添加 key 时,会使用多个 hash 函数对 key 进行 hash 算得一个整数索引值然后对位数组长度 进行取模运算得到一个位置,每个 hash 函数都会算得一个不同的位置。再把位数组的这几个位置都置为 1 就 完成了 add 操作。
在这里插入图片描述

二:缓存失效

由于大批量缓存在同一时间失效可能导致大量请求同时穿透缓存到达数据库,可能造成数据库瞬间压力过大甚至挂掉,对于这种情况我们在批量新增时最好将这一批数据的缓存时间设置为一个时间段内的不同时间。

    public String getCacheBreakDown(String key){
        // 从缓存汇总获取数据
        String cacheValue = (String) redisTemplate.opsForValue().get(key);
        if(null == cacheValue){
            // 从存储中获取
            String dbValue = getDbValue(key);
            int expireTime =  new Random().nextInt(300)+300;
            // 设置随机的过期时间
            redisTemplate.opsForValue().set(key,dbValue,expireTime,TimeUnit.SECONDS);
            return  dbValue;
        }

        return  cacheValue;
    }

三:热点Redis key重建

  • 当前key是一个热点key(例如一个热门的娱乐新闻),并发量非常大。
  • 重建缓存不能在短时间完成, 可能是一个复杂计算, 例如复杂的SQL、多次IO、 多个依赖等。

在缓存失效的瞬间, 有大量线程来重建缓存, 造成后端负载加大, 甚至可能会让应用崩溃。
要解决这个问题主要就是要避免大量线程同时重建缓存。

 public String getCacheHot(String key){
        String cacheVale =(String) redisTemplate.opsForValue().get(key);
        // 如果value 为 null ,则开始重构缓存
        if(null == cacheVale){
            // 加分布式锁解决热点缓存并发重建问题
            String muteNxKey = "mutex:key:"+key;
            RLock hotCreateCacheLock = redisson.getLock(muteNxKey);
             hotCreateCacheLock.lock();
             try{
                 String dbValue = getDbValue(key);
                 redisTemplate.opsForValue().set(key,dbValue,5*60,TimeUnit.SECONDS);
                 return  dbValue;
             }finally {
                 hotCreateCacheLock.unlock();
             }
        }
        return cacheVale;
    }

四:缓存与数据库双写不一致

这个是经常会遇到的一种情况,当我们一个进程插入数据的时候还没处理完成,另一个线程又进行了读取数据到缓存中。

  • 写写:两个线程进行写操作
  • 读写:一个线程进行读,一个线程写
    在这里插入图片描述
    在这里插入图片描述
    1.使用分布式锁解决
    public String  updateCacheDoubleWrite1(String key){
        RLock updateValeLock = redisson.getLock(key);
        updateValeLock.lock();
        String dbVale = null;
        try{
             dbVale = updateValue(key);
             redisTemplate.opsForValue().set(key,dbVale,getTimeout(),TimeUnit.SECONDS);
        }finally {
            updateValeLock.unlock();
        }
        return dbVale;
    }

2.使用Redis的读写锁解决,底层即为Lua脚本

    public String updateCacheDoubleWrite2(String key){
        RReadWriteLock updateWriteLock =  redisson.getReadWriteLock(key);
        RLock write =updateWriteLock.writeLock();
        write.lock();
        String dbVale = null;
        try {
            dbVale = updateValue(key);
            redisTemplate.opsForValue().set(key,dbVale,getTimeout(),TimeUnit.SECONDS);
        }finally {
            write.unlock();
        }
        return dbVale;
    }

五:缓存雪崩

缓存雪崩是指缓存支撑不住或宕机,流量全部打向后端数据库,导致系统整体挂掉。
预防和解决缓存雪崩问题,从以下几个方面考虑;

  • 保证缓存层服务高可用性,比如使用Redis Sentinel或Redis Cluster。
  • 依赖隔离组件为后端限流熔断并降级。比如使用Sentinel或Hystrix限流降级组件。进行服务的相关降级处理。
  • 在项目上线前, 演练缓存层宕掉后, 应用以及后端的负载情况以及可能出现的问题, 在此基 础上做一些预案设定。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

virtuousOne

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值