概述
缓存穿透(数据库查不到)
用户想要查询一个数据,发现redis中没有,也就是缓存没命中,于是向持久层数据库中查询,发现数据库中也没有,于是本次查询失败。当用户很多时候,缓存一直没有命中(比如秒杀场景),于是都去请求数据库了。这会给数据库造成很大的压力,这种场景就是缓存穿透(简单的说就是缓存和数据库中都没有某条数据,就会造成缓存穿透的情况)。
解决方案
对控制缓存
如果一个查询返回的数据为空(不管数据是否不存在),我们仍然把这个空结果(null)进行缓存,设置空结果的过期时间会很短,最长不超过5分钟。
但是这种方法会存在两个问题:
- 如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键。
- 即使对空值设置了过期时间,还是会在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要一致性的业务会有影响(可以通过在代码中添加删除相应key的缓存来解决不一致的问题,比如增加,修改了相应的key直接删除该key对应的缓存即可)。
设置可访问的名单(白名单)
使用bitmaps类型定义一个可以访问的名单,名单id作为bitmaps的偏移量,每次访问和bitmap里面的id进行比较,如果访问id不在bitmaps里面,进行拦截,不允许访问。
布隆过滤器
布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力。
进行实时监控(设置黑名单)
当发现Redis的命中率开始急速降低,需要排查访问对象和访问的数据,和运维人员配合,可以设置黑名单限制服务。
缓存击穿(量太大,缓存过期)
比如微博服务器在有热点事件时可能宕机。(同一时刻大量的访问在缓存中没有命中,砸向了数据库)。
概述
这里需要注意和缓存穿透的区别,缓存击穿是指一个Key非常热点,在不停的扛着大并发,大并发集中对着一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开一个洞。
当某个key在过期的瞬间,有大量的请求并发访问,这类书籍一般是热点数据,由于缓存过期,会同时访问数据库来查询最新数据,并且会写缓存,会导致使数据库瞬间压力过大。
解决方案
key可能会在某些时间点被超高并发地的访问,是一种非常“热点”的数据。这个时候,需要考虑一个问题:缓存被“击穿”的问题。
预先设置热门数据
在redis高峰访问之前,把一些热门数据提前存入到redis里面,加大这些热门数据key的时长。
实时调整
现场监控哪些数据热门,实时调整key的过期时长。
使用锁
- 就是在缓存失效的时候(判断拿出来的值是否为null),不是立即去load db。
- 加分布式互斥锁(缺点,性能低)
分布式锁:使用分布式锁,保证对于每个Key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,等待分布式锁释放。这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大。
缓存雪崩
问题描述
key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。
缓存雪崩与缓存击穿的区别在于这里针对很多key缓存,前者则是某一个key。
概念
缓存雪崩,是指在某个时间段,缓存集中过期失效或者redis宕机。
产生雪崩的原因之一,比如在双十一的时候,大量的用户会去抢购一波商品,这波商品时间比较集中的放入缓存,假设缓存过期时间是一个小时,那么1个小时后,这批商品的缓存都获取了,而对这波商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。于是所有的请求都会到达存储层,存储层的调用量暴增,造成存储层可能挂掉的情况。
解决方案
缓存失效时的雪崩效应对底层系统的冲击非常可怕!
构建多级缓存架构
nginx缓存 + redis缓存 + 其他缓存(ehcache)等。
其中某级缓存失效,不会导致数据库压力过大,但是架构比较复杂,一致性比较难保证。
使用锁或队列
用加锁或者队列的方式来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。但不适用高并发情况。
设置过期标志更新缓存
记录缓存数据是否过期(设置提前量),如果过期会触发通知另外的线程在后台去更新实际key的缓存。
将缓存失效时间分散开
比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集群实现的事件。
redis高可用
这个思想的含义是,既然redis有可能挂掉,那就增加几台redis,这样1台挂掉还有其他的可以继续工作,就是搭建redis集群(解决redis宕机引起的缓存雪崩问题),可以使用异地多活。
限流降级(SpringCloud中有限流降级解决方案,停掉某些服务,保证主业务可用)
这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量,比如对某个Key只允许一个线程查询数据和写缓存,其他线程等待。
数据预热
数据预热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀(解决因为缓存集中过期而引起的缓存雪崩问题)。
参考链接
https://www.bilibili.com/video/BV1S54y1R7SB?p=36
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/100428.html