三者出现的根本原因是:Redis缓存命中率下降,请求直接打到DB上了。
一、 缓存穿透:
1、定义:
缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库。所谓穿透,就是直接透过了redis,直接透到数据库。
2、原因:
比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。
3、解决方法:
(1)缓存空对象:
对空值缓存:如果一个查询返回的数据为空(不管是数据是否不存在),我们仍然把这个空结果(null)进行缓存,设置空结果的过期时间会很短,最长不超过五分钟。之后再访问这个数据将会从缓存中获取,保护了后端数据源。
优点:实现简单,维护方便;
缺点:
- 缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键;
- 可能造成短期的不一致;即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。
(2)布隆过滤:
使用BitMap作为布隆过滤器,将目前所有可以访问到的资源通过简单的映射关系放入到布隆过滤器中(哈希计算),当一个请求来临的时候先进行布隆过滤器的判断,如果有那么才进行放行,否则就直接拦截。
优点:内存占用较少,没有多余key;空间效率和查询时间都远远超过一般的算法;
缺点:实现复杂;一定的误识别率和删除困难。
还有一些其他解决方法,如:
(3)增强id的复杂度,避免被猜测id规律
(4)做好数据的基础格式校验
(5)加强接口校验
类似于用户权限的拦截,对于id=-1这些无效访问就直接拦截,不允许这些请求到达Redis、DB上。
(6)做好热点参数的限流
(7)实时监控:
对redis进行实时监控,当发现redis中的命中率下降的时候进行原因的排查,配合运维人员对访问对象和访问数据进行分析查询,从而进行黑名单的设置限制服务。
二、缓存雪崩
1、定义
大量key失效。缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。
2、产生原因:
redis中大量的key集体过期。
3、解决方法:
(1)将失效时间分散开
通过使用自动生成随机数使得key的过期时间是随机的,防止集体过期
(2)使用多级架构
使用nginx缓存+redis缓存+其他缓存,不同层使用不同的缓存,可靠性更强
(3)设置缓存标记
记录缓存数据是否过期,如果过期会触发通知另外的线程在后台去更新实际的key
(4)使用锁或者队列的方式
如果查不到就加上排它锁,其他请求只能进行等待
三、缓存击穿
1、定义:
缓存击穿问题也叫热点Key问题,指一个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击。
和缓存雪崩不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
2、产生原因:
redis中的某个热点key过期,但是此时有大量的用户访问该过期key。
3、逻辑分析:
逻辑分析:假设线程1在查询缓存之后,本来应该去查询数据库,然后把这个数据重新加载到缓存的,此时只要线程1走完这个逻辑,其他线程就都能从缓存中加载这些数据了,但是假设在线程1没有走完的时候,后续的线程2,线程3,线程4同时过来访问当前这个方法, 那么这些线程都不能从缓存中查询到数据,那么他们就会同一时刻来访问查询缓存,都没查到,接着同一时间去访问数据库,同时的去执行数据库代码,对数据库访问压力过大
3、解决方法:
(1)使用锁机制:
只有一个请求可以获取到互斥锁,然后到DB中将数据查询并返回到Redis,之后所有请求就可以从Redis中得到响应
(2)逻辑过期
采用逻辑过期方案。设置key永不过期,而把过期时间设置在 redis的value中,这个过期时间并不会直接作用于redis,而是我们后续通过逻辑去处理。
(3)提前对热点数据进行设置
类似于新闻、某博等软件都需要对热点数据进行预先设置在redis中
(4)监控数据,适时调整
监控哪些数据是热门数据,实时的调整key的过期时长