Redis之穿透、击穿、雪崩

Redis作为日常开发的高频组件,这里就一些常见的问题进行讨论

abstract.png

Cache Penetration 缓存穿透

定义

用户去查询一个缓存、数据库中均不存在的数据,导致所有的请求直接打到数据库上。例如数据库中记录的id是从1开始进行自增,此时如果攻击者使用-1的id进行暴力请求攻击,很有可能导致数据库由于压力过大而宕机

解决方案

  1. 接口层加入参数校验,直接过滤掉非法参数。例如本例中要求请求参数id必须为正数
  2. 当在数据库中未查询到数据时,将该key也存入到Redis中,只不过value是一个空标记。这样下次再请求时就不会经过数据库了。当然空标记数据的过期时间一般较短
  3. 在查询Redis之前,还可以使用Bloom Filter布隆过滤器。由于具有假阳的特点,即判定不存在则事实上一定不存在,但判定存在则事实上有可能不存在。此举即可大大减少Redis中空标记数据的数量

Hotspot Invalid 缓存击穿

定义

Redis中某个Key的访问频率非常高,即所谓的热点Key。一旦该热点Key过期失效了,即会导致大量的请求直接打到数据库上

解决方案

  1. 通过使用互斥锁来保证只有一个线程去查询数据库并回写到Redis中,其他线程将会睡眠直到缓存数据构建完毕。此时其他线程就可以从缓存中获取数据,避免直接访问数据库。集群环境下,可通过Redis的setnx命令实现分布式锁。该方案的数据一致性虽然可以得到保证,但是缺点也很明显,一方面是可能会导致线程池发生阻塞,另一方面其思想虽然比较简单,但实现一个可靠的分布式锁并不容易
  2. 将redis key设置为永不过期,而在该redis key对应的value中存储过期时间。然后通过后台的异步线程对缓存数据的有效性进行检查并更新。显然该方案无法保证一致性

Cache Avalanche 缓存雪崩

定义

由于 某个时刻Redis缓存同时发生大面积过期 或 Redis服务失效,导致大量的请求直接打到数据库上。严重时会导致数据库由于扛不住大流量直接挂了。此时即使立刻重启数据库也无济于事,其会立刻被一大波新的流量重新打挂

解决方案

  1. 在向Redis批量写入数据时,给每个Key的过期时间加上一个随机数,避免大量Key在同一时间失效
  2. 利用主从+哨兵、集群等手段保证Redis服务的高可用,避免Redis服务失效
  3. 采用多级缓存机制,例如Ehcache、Caffeine等本地缓存,实现与Redis的互相兜底
  4. 使用限流机制对数据库进行保护

参考文献

  1. Redis开发与运维 付磊、张益军著
0%