缓存穿透、击穿以及雪崩

b站讲缓存的视频
一些讲解缓存的书籍
开源项目
再结合实际。比如想想大佬开发的软件所展示出来的效果,想想那些公司啊。

学习就是不断迭代的过程,既然如此,那我就不需要害怕犯错。坚持总能出结果的。

击穿:一个高并发访问的时候,针对一个不存在的缓存数据的查询,由于缓存中没有相关的数据,导致这个查询直接落在数据库上,造成数据库的压力过大,导致数据库性能下降甚至宕机。比如我就故意用null或者其它缓存不存在的值去访问。

穿透:一个请求查询一个非常多缓存和数据库中都没有的数据时,这种情况下就会导致请求穿透到后端数据库,造成数据库的压力过大。讲人话,就是某热搜新闻,假设这里发生了缓存穿透,你说数据库会不会崩溃呢?

雪崩:某个时间段,缓存集中失效,而导致大量的请求直接落到数据库上,造成数据库的 压力过大,甚至引起数据库崩溃。

整个流程
请添加图片描述
类设计
请添加图片描述整个缓存查询流程,只有查询数据库那里会发生变化,我就简单的封装下:

/**
     * 执行搜索
     *
     * @param callback 回调
     * @param key      关键key
     * @param maxTime  最长时间
     * @param timeUnit 时间单位
     * @return {@link T}
     */
    @Override
    public <T> T executeSearch(ReadDataFromDbCallback<T> callback,String key,long maxTime, TimeUnit timeUnit) {
        // 无效数据的过滤,减少击穿。
        if(!codeGenerateCacheFilter.filter(key)){
            return null;
        }
        // 从远程redis缓存找,这里会有穿透,想办法识别并延长热点数据
        T result = codeGenerateCache.getCacheData(key);
        if(result != null){
            return result;
        }
        // 缓存找不到则从mybatis一二级缓存找,最后才会去数据库找。
        result = callback.readDataFromDb();
        if(result != null){
            // 缓存放入数据,可能有雪崩的隐患,里边已解决,maxTime+ThreadLocalRandom产生的随机数
            codeGenerateCache.putCacheData(key,result,maxTime,timeUnit);
            return result;
        }
        // 没有找到
        return null;
    }

使用例子

DeveloperInfo developerInfo = codeGenerateCacheOperations.executeSearch(() -> {
    DeveloperInfo result = developerInfoService.getById(id);
    return result;
}, "1001", 60*5, TimeUnit.SECONDS);
Assert.assertNotNull(developerInfo);

缓存更新
有修改/删除,直接删除。
先更新数据库,然后删除,再延时删除

/**
     * 执行更新
     *
     * @param callback 回调
     * @param key      关键key
     * @return {@link T}
     */
    @Override
    public <T> T executeUpdate(WriteDataToDbCallback<T> callback,String key) {
        T result;
        try{
            result = callback.writeDataToDb();
        }catch (Exception e){
            log.info("数据库更新执行异常",e);
            return null;
        }
        if(result != null){
            codeGenerateCache.deleteCacheData(key);
        }
        return result;
    }

使用例子

DeveloperInfo developerInfo = codeGenerateCacheOperations.executeSearch(() -> {
    DeveloperInfo result = developerInfoService.getById(id);
    return result;
}, "1001", 60*5, TimeUnit.SECONDS);
Assert.assertNotNull(developerInfo);

DeveloperInfo data = codeGenerateCacheOperations.executeSearch(() -> {
    // 这里已经有缓存,若走到这里则表示有问题
    Assert.fail();
    DeveloperInfo result = developerInfoService.getById(developerInfo.getUserId());
    return result;
}, "1001", 60*5, TimeUnit.SECONDS);
Assert.assertNotNull(data);

developerInfo.setUserName("lch_001");
codeGenerateCacheOperations.executeUpdate(() -> {
    boolean result = developerInfoService.updateById(developerInfo);
    if(!result){
        return null;
    }
    return developerInfo;
},developerInfo.getUserId());

List<DeveloperInfo> list = new ArrayList<>();
data = codeGenerateCacheOperations.executeSearch(() -> {
    DeveloperInfo result = developerInfoService.getById(developerInfo.getUserId());
    // 缓存已经被删除,应该要走这里
    list.add(result);
    return result;
}, "1001", 60*5, TimeUnit.SECONDS);
Assert.assertNotNull(data);
Assert.assertTrue(list.size()>0);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值