本文学习Redis应用问题中经典的缓存穿透、缓存击穿、缓存雪崩问题及常用的解决办法

1. 缓存穿透
  • 描述:key对应的数据在后端DB并不存在,每次针对该key的请求从Redis缓存获取不到,请求都会压到后端DB,从而可能压垮后端DB。
  • 原因举例:黑客url访问攻击
  • 解决方案:
  • 对空值缓存:如果一个查询返回数据为空,我们仍然对该空结果进行缓存,并且设置空结果过期时间在5分钟内
  • 设置白名单:使用bitmaps类型定义可访问的名单,名单id为bitmaps的偏移量,每次访问和bitmaps中id比较,如果不在bitmaps中,进行拦截
  • 采用布隆过滤器:使用bf.add添加与bf.exists判断是否存在拦截,也可实现,但是会有一定的误判
  • 实时监控:当运维系统检测到redis的命中率开始急速降低,需排查设置黑名单限制服务
2. 缓存击穿
  • 描述:key对应的数据在后端DB存在,但在redis中过期,此时若大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这时高并发请求可能瞬间把后端DB压垮
  • 解决方案:
  • 预先设置热点数据:在redis高峰访问之前,把一些热门数据提前存入到redis里面,并且加大热点数据key时长
  • 实时调整:现场监控哪些热门数据,实时调整key的过期时长
  • 使用分布式锁:缓存key失效时,不立即load db, 加锁成功后,在load db,并回设到缓存,最后释放锁。这样其他并发请求后续会从缓存中获取数据
3. 缓存雪崩
  • 描述:在某一时间段,缓存集中失效,导致请求全部走数据库,这时高并发请求可能瞬间把后端DB压垮
  • 原因举例:
  • redis服务器宕机
  • 对缓存数据设置了相同的过期时间,导致某时间段内缓存集中失效
  • 解决方案:
  • 针对redis服务器宕机,可以实现redis的高可用:Redis Cluster(集群模式)或Redis Sentinel(哨兵模式)
  • 将缓存失效时间分散开:设置缓存过期时间时加上一个随机值
  • 构建多级缓存架构:nginx缓存+redis缓存+其他缓存
  • 锁和队列控制:使用锁和队列来保证不会有大量线程对数据库一次性读写,不适宜高并发
  • 设置过期标志更新缓存:记录缓存数据是否将要过期(设置提前量),如果将要过期会触发通知另外线程去更新实际key的缓存

缓存击穿与缓存雪崩的区别是击穿针对的是某一热门key缓存,而雪崩针对的是大量缓存的集中失效