Redis缓存穿透和雪崩
Redis缓存的使用,极大地提升了应用程序的性能和效率,特别是数据查询方法,但同时,他也会带来一些问题,其中最要害的问题,就是数据的一致性问题,从严格上讲,这个问题是无解的,如果对数据的一致性要求很高,那么就不能使用缓存。
另外的一些典型问题就是,缓存穿透,缓存雪崩和缓存击穿,目前,业界都有比较流行的方法
缓存穿透(查不到数据)
原理
当用户想要查询一个数据时候,发现Redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询,发现也没有,于是查询失败,当用户很多时候,缓存都没有命中,于是都去请求持久层数据库,这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透
解决方法:
布隆过滤器
是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合条件就丢弃,从而避免了对底层存储系统的查询压力
缓存空对象
当存储层不命中后,即使返回的空对象也要将其缓存起来,同时会设置一个过期时间,之后在访问就会获取到这个空对象,保护了后端的数据
但是存在问题:
1.如果控制能够缓存起来,就代表需要更多的键来存储 因为我们可能会有很多的空值的键
2.即使对空值设置了过期时间,还是会存在缓存层和存储层数据会有一段时间窗口不一致,这对于需要一致性的业务有影响
缓存击穿(同一数据查的次数太多,缓存过期)
是指一个key非常热点,在不停的并发,并发集中一点进行访问,当这个key在失效的瞬间,持续的大并发就击破缓存,直接请求数据库
当某个key在过期的瞬间,有大量的请求并发访问,这类数据一般是热点数据,由于缓存过期,会同时访问数据库来查询最新数据,并且会写缓存,会导致数据库瞬间压力过大,击穿
解决方法:
热点永不过期
从缓存层看,没有设置过期的时间,所以不会出现热点key过期产生的问题
加互斥锁
分布式锁:使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁权限,因此只需要等待即可,这个方式将高并发的压力转移到分布式锁上,因此对分布式锁考验很大
缓存雪崩
指某一个时间段,缓存集中过期或者Redis宕机
比如写文本时候,马上到12点,很快迎来一波抢购,这波抢购时间比较集中的放入缓存,假设缓存一小时,那么到了凌晨一点,这批商品的缓存都过期了,那么商品的查询就会走数据库,对于数据库而言,就很产生周期性的压力波峰,于是所有的请求达到存储层,存储层的调用很多,造成存储层挂掉。
其中集中过期不是最致命的,致命的是缓存服务器的某个节点宕机或者断网,因为自然形成的雪崩,一定是在某个时间段集中创建缓存,这个时候,数据库也是可以顶住压力的,无非就是对数据库产生周期性压力,而宕机,对数据库服务器的压力不是可以预知的,很有可能压垮。
解决方法:
Redis高可用
多设几台Redis服务器,这样一台挂掉其余正常工作,就是搭建集群(异地多活)
限流降级:
在缓存失效后,通过加锁或者队列来控制读数据库写数据库的数量,比如某个key只允许一个线程查询数据和写缓存,其他线程等待
数据预热
在正式部署之前,我们先把可能的数据访问一遍,这样部分肯能大量访问的数据就会加载到缓存中,在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间尽量均匀