1、redis缓存穿透
概念
缓存穿透的概念很简单,用户想要查询一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询。发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中,于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。
解决方法
1、布隆过滤器:
将数据库中所有的查询条件,放入布隆过滤器中,
当一个查询请求过来时,先经过布隆过滤器进行查,如果判断请求查询值存在, 则继续查;如果判断请求查询不存在,直接丢弃。
布隆过滤器实际上上是一个二进制向量(位图)和一系列随机映射函数(哈希函数)。
布隆过滤器可以用于检索一个元素是否再一个集合中。它的优点是空间效率和查询时间都远超过一般的算法,缺点是有一定的误识别率和删除困难。
它将所有可能存在的数据通过哈希函数到放到一个足够大的bitmaps中,一个一定不存在的数据会被拦截掉,从而避免对底层存储系统的查询压力
2、缓存空对象
但是这种方法会存在两个问题:
(1)如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键;
(2)即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。
3、设置白名单
使用bitmaps类型定义一个可以访问的白名单,名单id作为bitmaps的偏移量,每次访问和bitmaps里面的id进行比较,如果访问id不在bitmaps里面,则不允许访问。
4、实时监控
当发现redis的命中率开始急剧降低,需要排查访问对象和访问的数据,和运维人员配合,可以设置黑名单限制服务。
2、redis缓存击穿
概念
缓存击穿,是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。
解决方法
- 预先设置热门数据
在redis高分访问之前,把一些热门数据提前存入到redis中,加大这些数据key的时长
- 使用互斥锁(mutex key)
业界比较常用的做法,是使用mutex。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法。
SETNX,是「SET if Not eXists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果。
3、redis缓存雪崩
概念
缓存雪崩是指,缓存层出现了错误,不能正常工作了(如大量key过期)。于是所有的请求都会达到存储 层,存储层的调用量会暴增,造成存储层也会挂掉的情况,(redis中也会设置数据有效时长,当大批数据数据失效时,直接访问持久层也会出现该情况)
解决方案
(1)redis高可用
这个思想的含义是,既然redis有可能挂掉,那我多增设几台redis,这样一台 挂掉之后其他的还可以继续工作,其实就是搭建的集群。
(2)限流降级
这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
(3)设置过期标志更新缓存
记录缓存数据是否过期(设置提前量),乳沟过期会触发通知另外的线程在后台更新实际key的缓存
(4)构建多级缓存架构
nginx缓存+redis缓存+其他缓存(chcahe等)
(5)将缓存失效时间分开
可以在原有的失效时间基础上增加一个随即值,这样每一个缓存的过期时间的重复率会降低,避免集体失效