关于:缓存穿透、缓存击穿、缓存雪崩、热点数据失效

来自Wikioe
Eijux讨论 | 贡献2020年10月28日 (三) 03:54的版本 →‎缓存雪崩
跳到导航 跳到搜索


关于

项目通常会引入NoSQL技术(即:基于内存的数据库,如redis),来应对大数据量的需求,以规避磁盘读/写速度比较慢的问题而存在的性能弊端;
但是,引入redis等又有可能出现缓存穿透,缓存击穿,缓存雪崩等问题,并需要开发对这些问题进行考量并作出应对。

缓存穿透

缓存穿透:请求一个不存在的数据,缓存和数据库都查不到这个数据,每次都会去数据库查询。

比如:用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。

解决方案

有很多种方法可以有效地解决缓存穿透问题:

  1. BloomFilter:(“布隆过滤器”)将所有可能存在的数据哈希到一个足够大的bitmap中,每次查询的时候都先去BloomFilter判断,如果没有就直接返回null。
    • 注意BloomFilter没有删除操作,对于删除的key,可以在缓存中缓存null;
  2. 缓存空值:如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),仍然为这些key在缓存中设置对应的值为null
    • 要对这些key设置过期时间,以防止真的有数据;
    //伪代码
    public object GetProductListNew() {
        int cacheTime = 30;
        String cacheKey = "product_list";
    
        String cacheValue = CacheHelper.Get(cacheKey);
        if (cacheValue != null) {
            return cacheValue;
        }
    
        cacheValue = CacheHelper.Get(cacheKey);
        if (cacheValue != null) {
            return cacheValue;
        } else {
            //数据库查询不到,为空
            cacheValue = GetProductListFromDB();
            if (cacheValue == null) {
                //如果发现为空,设置个默认值,也缓存起来
                cacheValue = string.Empty;
            }
            CacheHelper.Add(cacheKey, cacheValue, cacheTime);
            return cacheValue;
        }
    }
    
  • BloomFilter可以结合缓存空值用;

缓存击穿

缓存击穿:大量的请求同时查询同一个key时,此时这个key正好失效了,就会导致同一时间,这些请求都会去查询数据库,这样的现象我们称为缓存击穿。

解决方案

  1. 采用分布式锁,只有拿到锁的第一个线程去请求数据库,然后插入缓存,当然每次拿到锁的时候都要去查询一下缓存有没有;

缓存雪崩

缓存雪崩:当某一时刻发生大规模的缓存失效的情况,如缓存服务宕机。

解决方案

针对服务器宕机:

  1. 采用集群,降低服务宕机的概率;
  2. ehcache本地缓存 + Hystrix限流&降级;【???】
    • ehcache 本地缓存:在 Redis Cluster 完全不可用的时候,ehcache 本地缓存做临时支持;
    • Hystrix进行限流 & 降级 ,比如一秒来了5000个请求,我们可以设置假设只能有一秒 2000个请求能通过这个组件,那么其他剩余的 3000 请求就会走限流逻辑;

热点数据失效

解决方案