缓存穿透
概念
缓存穿透是指不断的请求缓存中不存在的数据, 则所有请求全部落在了数据库层, 高并发的情况下, 就直接影响了整个系统的业务, 甚至可能导致系统崩溃
过程
- 根据key从缓存中获取数据;
- 如果数据不为空,直接返回;
- 如果数据为空,进行数据库查询;
- 如果从数据库查询出的数据不为空,则放入缓存(设定过期时间)
不断的重复第三步, 比如要查一个商品的信息, 传入 -1
, 所有请求就直接落在了数据库上
解决
- 设置空对象缓存
数据库取出来的数据如果是空值, 同样也缓存, 但是设置一个比较短的缓存时间, 这样可以一定意义上减缓缓存穿透 - 布隆过滤器
布隆过滤器本质上一种空间效率极高的概率型算法和数据结构,主要用来判断一个元素是否在集合中存在。
// 使用
可以提前将真实正确的key,在添加完成之后便加入到过滤器当中,每次再进行查询时,先确认要查询的key是否在过滤器当中,如果不在,
则说明key为非法key,则不需要进行后续的查询步骤了。
缓存雪崩
概念
缓存雪崩是指缓存中数据大批量同一时间过期或者redis服务挂了,而查询数据量巨大,引起数据库压力过大。
过程
- 商城中缓存了商品的信息,时间为24小时
- 在第二天的0点, 正好有一个抢购活动
- 抢购开始的时候, 全部缓存失效, 同一时间全部的商品信息查询落到数据库上, 导致可能压力过大
解决
- 可以在做数据缓存的时候, 按分类进行缓存, 添加不同的缓存时间
- 缓存的同时, 对缓存时间加上一个随机数, 以至于不会让所有缓存同一时间大量失效
- 对于redis服务挂掉的问题,可以实现redis的高可用主从架构, 并且做redis的持久化, 在redis挂掉的同时时读取本地缓存数据, 同时恢复redis服务加载持久化的数据
缓存击穿
概念
缓存击穿和缓存雪崩有点像, 不过不是大面积的缓存失效
缓存击穿指的是缓存中某一个key的值不断的接收着大量的请求, 而在这个key值失效的瞬间, 大量的请求落在了数据库上, 从而导致数据库可能压力过大
过程
- 有key1,key2…等键值对应的缓存
- key1属于热度商品, 不断的扛着请求
- key1过期时间到了, 请求瞬间落在了数据库上, 导致可能压力过大
解决
- 加分布式锁或者分布式队列
用加分布式锁或者分布式队列的方式保证缓存的单线程写,从而避免失效时大量的并发请求落到底层存储系统上。在加锁方法内先从缓存中再获取一次(防止另外的线程优先获取锁已经写入了缓存),没有再查DB写入缓存。 (当然也可以: 在没有获取锁的线程中一直轮询缓存,至超时) - 添加超时标记
在缓存的对象上增加一个属性来标识超时时间,当获取到数据后,校验数据内部的标记时间,判定是否快超时了,如果是,异步发起一个线程(控制好并发)去主动更新该缓存。 - 另外还有一个粗暴的方法,如果你的热点数据要求实时性比较低,那么可以设置热点数据在热点时段不过期,在访问低峰期过期,比如每天凌晨过期。
Redis