Redis缓存雪崩、缓存穿透、缓存击穿

338 阅读3分钟
原文链接: blog.csdn.net

Redis缓存

前言

在互联网应用上,Redis使用越来越广泛,甚至传统企业应用也是如此。高性能的读取能力,广受程序员的喜爱。一般而言,都是先从Redis里读取数据,如果数据存在,则直接返回数据,否则,就从DB里读取(如下图)。但由于Redis的key的失效时间、不存在的key、网络问题或其他问题导致Redis崩溃等情况,会直接去访问数据库,这个时候如果是高并发访问,会导致Redis压力增大,甚至系统瘫痪。于是就有了缓存雪崩、缓存穿透、缓存击穿的问题。
在这里插入图片描述

缓存雪崩

缓存雪崩,指的是大面积缓存失效。大量key在同一时间没失效,此时大量的并发涌入,redis访问失效,会直接访问DB,从而导致数据库负载甚至瘫痪。另外也有可能是Redis宕机了,这个时候也会直接访问数据库,产生缓存雪崩的现象。

解决方案

应用程序

  • 热点数据设置永不过期。比如商品的首页数据,商品的分类等静态数据。
  • 缓存失效时间,在原来基础上添加一个随机值setRedis(Key,value,time + Math.random() * 1000)
  • 双缓存策略,一个缓存失效时间为短期的,另一个为永久的。当短期失效时间时,再去读取永久的。
  • 缓存预热:在上线前,就把可能需要访问的数据预先访问然后存到数据库里。其实就是手动触发触发。

挂机

  • 事前

    保证高可用。选择合适的内存淘汰策略。如果有Redis机器宕机,可以直接补上。Redis高可用常见方式一般也就两种:

    1. 主从复制(Repication-Sentinel)
    2. Redis集群(Redis_Cluster)
  • 事中

    使用本地缓存ehchace或guava cache或caffine cache + hystrix限流或降级,避免MySQL崩溃

  • 事后

    利用Redis的持久化机制,保存的数据能够快速恢复

缓存穿透

缓存穿透主要是针对不存在的key,查询Redis时不存在,然后直接访问DB,DB也不存在。这样每次都是去访问数据库,就像桶捅破了一个洞,如果流量超大时,会导致Redis和数据库压力过大,甚至缓存雪崩。

解决方案

  • 接口层添加参数校验,鉴权校验等,不合法的参数直接Return。

  • 布隆过滤器,在请求访问缓存前,就排除掉非法的key。当然布隆过略会存在一定误判。

在这里插入图片描述

  • 不存在的key的结果null直接缓存起来,这样就不用访问DB了。

    但这种方法并不推荐,首先要保证数据的一致性,由于时间窗口的问题,可能新增的数据在缓存之前本不存在,这个时候去访问缓存结果肯定是null,如果存了null,也永远查不出来,所以不满足强一致性。然而缓存一般都是最终一致性,当然,如果你非要,可以添加缓存的过期时间,并且时间要短些,比如3秒,否则导致正常的功能无法使用。另外,也意味着需要更多的存储空间来存储空置的键
    在这里插入图片描述

缓存击穿

缓存击穿主要是针对一条热点数据,大量的并发持续访问,比如电商的爆款货,当这个key缓存失效时,直接穿透缓存,去访问db,就像一个桶捅破了一个洞。导致缓存压力负荷,甚至缓存雪崩。

解决方案

  • 互斥锁。 利用重入锁tryLock,当多个线程并发并发访问是,依次等待锁释放后再访问数据库。Java的Sychronized、lock,mechache的add,Redis的setnx都可以实现.

    1. memcache
      在这里插入图片描述

    2. Redis
      在这里插入图片描述

  • 缓存时间设置永久

在这里插入图片描述