八股文:Redis之缓存穿透、击穿、雪崩问题

108 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情

缓存穿透

缓存穿透是指查询缓存和DB中都不存在的数据。

通过id查询,id一般大于0,攻击者会故意传id为-1去查询,由于缓存是不命中则从DB中获取数据,这将会导致每次缓存都不命中数据导致每个请求都访问DB,造成缓存穿透。

解决方法:

  1. 接口层增加校验,如鉴权校验。
  2. id做校验,id<=0的直接拦截。
  3. 从缓存取不到的数据,在数据库中也没有取到,就将key-value对写为key-空对象。以此防止攻击者反复用同一个id暴力攻击。
  4. 使用缓存预热,缓存预热就是将数据提前加入到缓存中,当数据发生变更,再将最新的数据更新到缓存。
  5. 利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库。没得到锁,则休眠一段时间重试。
  6. 利用布隆过滤器,内部维护一系列合法有效的key。迅速判断出,请求所携带的Key是否合法有效。如果不合法,则直接返回。

缓存击穿

缓存击穿是指缓存中没有但数据库中有的数据。

由于某个时刻并发用户量非常大,同时读缓存没读到数据,又同时去数据库获取数据,引起数据库压力瞬间增大,造成过大压力。

解决方案:

  1. 设置热点数据永远不过期。
  2. 缓存预热。
  3. 数据不设置过期时间,在缓存的对象上添加一个属性标识过期时间,每次获取到数据时,校验对象中的过期时间属性,如果数据即将过期,则异步发起一个线程主动更新缓存中的数据,当然也可能拿到过期的值,看具体需求。

缓存雪崩

缓存雪崩是指缓存数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至宕机。

缓存中如果大量缓存在一段时间内集中过期了,这时候会发生大量的缓存击穿现象,所有的请求都落在了DB上,由于查询数据量巨大,引起DB压力过大甚至导致DB宕机。

解决方案:

  1. 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。如果Redis是集群部署,将热点数据均匀分布在不同的Redis库中也能避免全部失效的问题。
  2. 设置热点数据永远不过期。
  3. 使用缓存预热。
  4. 使用互斥锁,但是该方案将导致吞吐量明显下降。

三者区别

缓存穿透: 通常请求携带有参数,不断发起请求。

缓存击穿: 通常是某个时刻并发大量请求,并发查询同一条数据。

缓存雪崩: 缓存不同的数据大批量到过期时间,很多数据都查不到从而查数据库。

缓存预热

缓存预热是将数据提前加入到缓存中,当数据发生变更,再将最新的数据更新到缓存。