redis缓存穿透、击穿、雪崩
一、缓存穿透
当客户端查询一个数据,发现redis内存数据库没有,也就是缓存没有命中。于是向持久层数据库查询,发现也没有,出于容错考虑,本次查询不写入缓存。当用户很多的时候,缓存都没有命中,于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就出现了缓存穿透。
解决方案:
1、布隆顾虑器(布隆过滤器可以用于检索一个元素是否在一个集合中)
首先也是对所有可能查询的参数以hash形式存储,当用户想要查询的时候,使用布隆过滤器发现不在集合中,就直接丢弃,不再对持久层查询。
2、设置默认值
当存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,时间很短,几分钟。之后再访问这个数据将会从缓存中获取,保护了后端数据源。
但是这种方法会存在两个问题:
(1)如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键;
(2)即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。
二、缓存雪崩
缓存雪崩是指,缓存层出现了错误,例如数据未加载到缓存中,或者缓存同一时间大面积失效。于是所有的请求都会达到存储层,存储层的调用量会暴增,导致数据库CPU和内存负载过高,甚至宕机。
比如一个雪崩的简单过程:
1、redis集群大面积故障
2、缓存失效,但依然大量请求访问缓存服务redis
3、redis大量失效后,大量请求转向到mysql数据库
4、mysql的调用量暴增,很快就扛不住了,甚至直接宕机
5、由于大量的应用服务依赖mysql和redis的服务,这个时候很快会演变成各服务器集群的雪崩,最后网站彻底崩溃。
解决方案:
(1)redis高可用
搭建高可用的redis集群,防止缓存大面积故障。
(2)缓存大面积失效
避免缓存设置相近的有效期;为有效期增加随机值;统一规划有效期,失效时间均匀分布。
三、缓存击穿
缓存击穿,是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,这里的key是某一个key(缓存雪崩是指多个key)。
解决方案:
1、使用分布式缓存支持的互斥锁(mutex key),去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存,也就是load DB 只会一个线程处理;(缺点:代码复杂度增大、存在死锁的风险、存在线程池阻塞的风险)
3、设置热点数据永不过期;