Redis缓存穿透

(1)正常的缓存穿透使用场景是,所有的查询请求先经过缓存,当缓存命中后,直接返回缓存中的数据;在缓存未命中的清空下,去数据库查询数据,并写入缓存。缓存的目的是为了尽可能将请求在缓存层处理,避免大量的请求进入缓存层,以达到保护缓存层的效果,如下图所示:

                     

通常我们可以在应用程序中分别统计总调用数,缓存层命中数和存储层命中数。如果发现大量存储层命中,有可能就出现了存储层穿透。造成缓存穿透的原因有以下两点:

应用程序自身的问题,如缓存设计或者数据存储问题。

黑客恶意攻击,已感染网络爬虫等。

(2)下面分析常用的缓存穿透问题的解决方案

1.缓存空对象

如下图(1-1)中,由于存储层大量的请求不能命中,无法填充缓存层,造成了恶性循环。缓存空对象的方式,就是在存储层未命中的情况下,仍然将空对象存储到缓存层中,之后再次访问到这条数据将会在缓存层中命中,有效的保护了缓存层。缓存空对象的架构设计图如下(1-2)所示:

缓存空对象的解决方案有两个问题: 第一个问题是缓存为空会存储更多的空对象,因此缓存层需要更多的存储空间,比较有效的办法是为这类数据设计合理的"过期时间" ,节约缓存层的空间;第二个问题是缓存层和存储层会出现数据一致性问题,即在缓存有效期内,存储层这个数据可能已经被更新,此时可以使用消息队列或者其他当时刷新缓存层的对象。下面是缓存空对象这种解决方案的伪代码:

/**
* 根据key查询对象,缓存空对象
*
***/
public Object get(String key){
    // 获取缓存中的数据
    Object cacheValue = cache.get(key);
    // 缓存为空
    if (cacheValue == null) {
         // 获取缓存层数据
         Object storeValue = db.get(key);
         //存储层未命中,设置空对象
         if(storeValue ==null){
            storeValue = new Blank(); // 构造一个保底的空对象
         }
          // 存储层数据写入缓存
         cache.set(key,storeValue);
         // 如果storeValue为空对象Blank 类型,设置超时时间为600s
         if(storeValue instanceof Blank){
              cache.expire(key,60*10); 
         }
         return storeValue;

    }
    // 缓存非空直接返回
    return cacheValue;
    


}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值