缓存雪崩

通常,我们为了保证缓存中的数据和数据库中的数据的一致性,会给redis里的数据设置过期时间,当缓过过期后,用户访问的数据如果不在缓存中,业务系统需要生成缓存,会访问DB并更新到Redis中。

大量缓存同一时间过期Redis故障宕机时,大量用户请求无法在Redis中处理,全部都会访问DB,从而导致数据库压力激增,严重还会导致数据库宕机,从而造成一系统反应,造成系统崩溃,这就是缓存雪崩。

原因

  1. 大量数据同时过期
  2. Redis故障宕机

解决方案

  • 针对大量数据同时过期:

    1. 均匀设置过期时间

      给数据过期时间加个随机数,不让他们在同一时间过期

    2. 互斥锁

      如果访问的数据不在Redis中,仅允许同一时间有一个请求来构建缓存

    3. 多key备份

      设置一个不会过期的备key,副本。

    4. 后台定时更新

  • 针对Redis故障宕机

    1. 服务熔断或请求限流机制
    2. 搭集群

缓存击穿

业务系统中,通常有几个数据会被频繁访问,如果其中某个热点数据过期了,无法从缓存中获取,那么请求就会访问到数据库中,很容易被高并发冲垮,这就是缓存击穿。

解决方案:

  • 互斥锁
    • 保证同一时间只有一个业务线程更新缓存,未能获取互斥锁的请求,要么等待锁释放后重新读取缓存,要么返回空/默认值
  • 不能热点数据过期,在后台更新

缓存穿透

当用户访问的数据既不在缓存中,也不在数据库中。当请求在访问缓存时,出现缓存缺失,再访问数据库,发现数据库也没有访问的数据,无法构建缓存数据。当有大量请求来临时,数据库压力骤增,这就是缓存穿透的问题。

解决方案

  • 对非法请求的限制

    当有大量恶意请求访问不存在的数据时,也会发生缓存穿透。在API入口处可以判断请求参数是否合理,有没有非法值,请求字段是否存在等,如果有恶意请求直接返回错误。

  • 缓存空值或默认值

    针对查询的数据,给缓存设置一个空值或默认值,这样后续的请求就可以从缓存中读取到空值或默认值,返回

  • 布隆过滤器

    对写入数据库的数据,使用布隆过滤器做标记,在用户请求到来时,业务线程确认缓存失效后,通过查布隆过滤器快速判断数据是否存在,如果不存在,就不用查DB

布隆过滤器

它由【初始值为0的位图数组】和【N个哈希函数】缓存,当我们在写入数据库时,在布隆过滤器做个标记,这样下次查询数据库是否在数据库时,只要查布隆过滤器就行。

  1. 用N个哈希函数对数据作哈希处理,得到N个哈希值
  2. 将N个哈希值对位图数组长度取模,得到每个哈希值在位图数据中的位置
  3. 把它们置为1

当查询时,如果查到各个数据都为1,就说明数据可能存在;如果有一个0,就说明数据肯定不存在。