Redis 缓存穿透缓存雪崩和缓存击穿
Posted 咖啡加糖
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis 缓存穿透缓存雪崩和缓存击穿相关的知识,希望对你有一定的参考价值。
1.缓存穿透
缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。
解决:缓存空对象、布隆过滤器、mvc拦截器
2.缓存雪崩
缓存雪崩是指在我们设置缓存时key采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩。
解决方案:
规避雪崩:缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
如果缓存数据库是分布式部署,将热点数据均匀分布在不同缓存数据库中。
设置热点数据永远不过期。
出现雪崩:降级 熔断
事前:尽量保证整个 redis 集群的高可用性,发现机器宕机尽快补上。选择合适的内存淘汰策略。
事中:本地ehcache缓存 + hystrix限流&降级,避免mysql崩掉
事后:利用 redis 持久化机制保存的数据尽快恢复缓存
3.缓存击穿
缓存雪崩和缓存击穿不同的是:
缓存击穿 指 并发查同一条数据。缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
解决方案:
设置热点数据永远不过期。
加互斥锁:业界比较常用的做法,是使用mutex。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db去数据库加载,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法。
redis 学习 -- 缓存雪崩缓存击穿和缓存穿透
文章目录
1、缓存处理流程
前台请求,
先从 缓存中 取数据,
如果 取到,则直接返回结果,
如果 取不到时,去数据库中查询,数据库取到后,更新缓存,并返回结果; 如果数据库也没取到,那直接返回空结果。
2、缓存穿透
2.1、描述
缓存穿透 是指查询一个一定不存在的数据,由于在缓存不存在,需要到数据库查询,数据库中也查不到,所以无法写入缓存,这样每次请求这个不存在的数据时都要到数据库去查询,从而可能压垮数据源。
在缓存和数据库中都没有的数据,而用户不断发起请求,如发起为 id为“-1” 的数据或 id为特别大且不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。
特点:
- 要查询的数据根本(如
id=-1
) 就不存在; - 缓存和数据库中也不存;
- 不停地查询数据库,可能压跨数据库。
2.2、解决办法
-
对空值缓存:
通常对缓存中不存在的、数据库中也不存在的数据不进行缓存,但是这也导致了每次都要查询数据库,给数据库造成巨大的压力。
如果一个查询返回的数据为空(不管是数据是否不存在),我们仍然把这个空结果(null)进行缓存,设置空结果的过期时间会很短,最长不超过五分钟。这样在缓存阶段进行拦截,减少应用程序和数据库的压力。
举个例子,比如 id=28888 在缓存和数据库中不存在,第一次数据库查询后也要进行缓存,后面多次请求这个数据时,可以直接跳转到空页等,避免再次查询数据库,减小应用程序压力。 -
设置可访问的名单(白名单):
使用 bitmaps 类型定义一个 可以访问的名单 ,名单 id 作为 bitmaps 的偏移量。每次访问 id 和 bitmap 里面的id进行比较,如果访问 id 不在 bitmaps 里面,进行拦截,不允许访问。 -
采用布隆过滤器(Bloom Filter):
布隆过滤器 是1970年由布隆提出的。它实际上是一个很长的二进制向量(位图)和一系列随机映射函数(即Hash哈希函数)。
布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是 空间效率和查询时间都远远超过一般的算法,缺点是 有一定的误识别率和删除困难。
将所有可能存在的数据哈希到一个足够大的 bitmaps 中,一个一定不存在的数据会被 这个 bitmaps 拦截掉,从而避免了对底层存储系统的查询压力。
布隆过滤器 底层与 bitmaps 一样,只是对 bitmaps 过程进行了优化。 -
进行实时监控:
当发现Redis的命中率开始急速降低,需要排查访问对象和访问的数据,和运维人员配合,可以设置黑名单限制服务。
3、缓存击穿
3.1、描述:
缓存击穿是指某一个key, 缓存中没有(可能是缓存到期,失效了),数据库中有的数据,这时大量访问中,都使用这个key,缓存没此数据,就是数据库中查询,引起数据库压力瞬间增大,造成过大压力。
特点:
- 针对一个key,在缓存中没有(可能是缓存到期,失效了);
- 数据库中有的数据;
- 针对这一个key,大量请求去查询数据库(实际上只查询一次,放到缓存里即可)。
3.2、 解决方案:
-
预先设置热门数据: 在redis高峰访问之前,把一些热门数据提前存入到redis里面,加大这些热门数据key的时长
-
调整过期时间: 现场监控哪些数据热门,实时调整key的过期时长
-
加互斥锁,互斥锁参考代码如下:
代码运行说明:1)缓存中有数据,直接走上述代码13行后就返回结果了 2)缓存中没有数据,第1个进入的线程,获取锁并从数据库去取数据,没释放锁之前, 其他并行进入的线程会等待100ms,再重新去缓存取数据。 这样就防止都去数据库重复取数据,重复往缓存中更新数据情况出现。 3)当然这是简化处理,理论上如果能根据key值加锁就更好了, 就是线程A从数据库取key1的数据并不妨碍线程B取key2的数据,上面代码明显做不到这点。
4、缓存雪崩(缓存数据集体失效)
4.1、 描述
大量的缓存数据 集中失效,此时有大量并发请求过来,这些请求发现缓存过期,程序都会从数据库 加载数据,更新缓存,并返回结果,如果大量请求可能会瞬间把 数据库压垮 。
特点:
- 大量缓存集中失效;
- 大量查询数据库,可能压跨数据库。
4.2、缓存击穿和缓存雪崩 的区别:
缓存击穿:并发地查询同一条数据;
缓存雪崩:不同数据都过期了,很多数据都查不到从而查数据库。
4.3、解决方案
缓存失效时的雪崩效应对底层系统的冲击非常可怕!
解决方案
- 缓存失效时间分散开,防止同一时间大量数据过期。
- 如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。
- 设置热点数据永远不过期。
5、参考来源:
以上是关于Redis 缓存穿透缓存雪崩和缓存击穿的主要内容,如果未能解决你的问题,请参考以下文章
REDIS12_缓存雪崩缓存穿透基于布隆过滤器解决缓存穿透的问题缓存击穿基于缓存击穿工作实际案例