redis
最常用的场景
核心思路就是把一些常用的数据,放到触手可及(访问速度更快)的地方
速度快的设备,可以作为速度慢的设备的缓存
CPU 寄存器 > 内存 > 硬盘 > 网络
最常见的是,使用内存作为硬盘的缓存(redis
定位)
硬盘也可以作为网络的缓存——浏览器的缓存
http/https
从服务器上获取到数据(html
、css
、js
、图片、视频、音频、字体…)并进行展示 缓存能够有意义,二八定律
20%
的数据,可以应对 80%
的请求通常是使用 redis
作为数据库的缓存(MySQL
)
MySQL
的速度又比较慢为什么说关系型数据库性能不高?
SQL
的执行会做一系列的解析,校验,优化工作因为 MySQL
等数据库,效率比较低,多以承担的并发量就有限,一旦请求数多了,数据库的压力就会很大,甚至很容易就宕机了
如何提高 MySQL
能承担的并发量?(客观需求)
MySQL
了redis
上只能存少数数据,但是大部分请求都是使用的这少数的热点数据3:7
,1:9
无所谓,基本思想是一致的如何知道 redis
中应该存储哪些数据?
如何知道哪些数据是热点数据呢?
这里就要谈到“缓存的更新策略“
会把访问的数据,以日志的形式记录下来
比如一个搜索引擎,“查询词”就是要关注的“访问的数据”
20%
的词,就可以把这些词认为是“热点词” Hadoop
的 map-reduce
来写代码进行统计;也可以基于 HDFS
的 HBASE
这样的数据库来写 SQL
统计redis
”这样的缓存中了此处的数据,就可以根据当前这里统计的未读,来定期更新
shell
,Python
写脚本代码),可以通过定时任务来触发优点:上述过程,实际上实现起来比较简单,过程更可控(缓存中有什么是比较固定的),方便排查问题 缺点:实时性不够。如果出现一些突发性时间,有一些本来不是热词的内容,成了热词了,新的热词就可能会给后面的数据库什么的带来比较大的压力
redis
查到了,就直接返回redis
中不存在,就从数据库查,把查到的结果同时也写入 redis
这样不停地写 redis
,就会使 redis
的内存占用越来越多,就会逐渐达到内存上限
redis
中也可以配置,最多使用多少内存(maxmermory
参数)如果继续往里插入数据,就会触发问题,为了解决上述问题,redsi
就引入了“内存淘汰策略”
#高频面试
FIFO
(First In First Out
)先进先出
把缓存中存在时间最久的(也就是先来的数据)淘汰掉
LRU
(Least Recently Used
) 淘汰最久未使用的
记录每个 key
的最近访问时间,把最近访问时间最老的 key
都淘汰掉
LFU
(Least Frequently Used
)淘汰访问次数最少的
记录每个 key
最近一段时间的访问次数,把访问次数最少的淘汰掉
Random
随机淘汰
从所有的 key
中抽取幸运儿被随机淘汰
理解上述几种淘汰策略: 想象你是个皇帝,有后宫佳丽三千。虽然你是真龙天子,但是经常宠信的妃子也就那么寥寥数人(后宫佳丽散散,相当于数据库中的全量数据,经常宠信的妃子相当于热点数据,是放在缓存中的) 今年选秀的一批新的小主,其中一个被你看上了,宠信新人,自然就需要有旧人被冷落,到底谁是要被冷落的人呢?
FIFO
:皇后是最先受宠的,现在已经年老色衰了==>皇后失宠LRU
:统计最近宠幸时间,皇后(一周前),熹妃(昨天),安答应(两周前),华妃(一个月前)==>华妃失宠LFU
:统计最近一个月的宠幸次数,皇后(3 次),熹妃(15 次),安答应(1 次),华妃(10 次)==>安答应失宠(最合理)Random
:随机挑选一个妃子失宠(最不合理)
具体采取哪种策略,要结合实际场景来具体问题具体分析redis
里面,有一个配置项,就可以设置 redis
采取上述哪种策略淘汰内存数据
volatile-lru
当内存不⾜以容纳新写⼊数据时,从设置了过期时间的 key
中使⽤ LRU
(最近最少使⽤)算法进⾏淘汰
allkeys-lru
当内存不⾜以容纳新写⼊数据时,从所有 key
中使⽤ LRU
(最近最少使⽤)算法进⾏淘汰.
volatile-lfu
4.0版本新增,当内存不⾜以容纳新写⼊数据时,在过期的 key
中,使⽤ LFU
算法进⾏删除 key
.
allkeys-lfu
4.0版本新增,当内存不⾜以容纳新写⼊数据时,从所有 key
中使⽤ LFU
算法进⾏淘汰.
volatile-random
当内存不⾜以容纳新写⼊数据时,从设置了过期时间的 key
中,随机淘汰数据.
allkeys-random
当内存不⾜以容纳新写⼊数据时,从所有 key
中随机淘汰数据.
volatile-ttl
在设置了过期时间的 key
中,根据过期时间进⾏淘汰,越早过期的优先被淘汰.(相当于 FIFO
, 只不过是局限于过期的 key
)
key
,很可能是没有保存设置时间的noeviction
默认策略,当内存不⾜以容纳新写⼊数据时,新写⼊操作会报错.
经过一段时间的“动态平衡”,redis
中的 key
就逐渐都成了热点数据了
#高频面试 缓存中的数据
redis
服务器首次接入之后,服务器里面是没有数据的
redis
,如果没有查到,就再查一次 MySQL
,查到了之后,会把数据也写到 redis
中MySQL
,随着时间的推移,redis
上的数据越积累越多,MySQL
承担的压力就逐渐减小了缓存预热,就是用来解决上面问题的
把定期生成和实时生成结合一下。先通过离线的方式,通过一些统计的途径,先把热点数据找到一批,导入到 redis
中。此时导入的这批热点数据,就能帮 MySQL
承担很大的压力了。随着时间推移,逐渐就使用新的热点数据淘汰掉旧的数据
#高频面试
查询的某个 key
,在 redis
中没有,MySQL
中也没有,这个 key
肯定也不会被更新到 redis
中
MySQL
带来很大的压力为何产生?
key
也被进行查询了 如何解决?
通过改进业务/加强监控报警等方式,都是亡羊补牢
相比之下更靠谱的方案:(降低问题的严重性**)
key
在 redis
和 MySQL
上都不存在,仍然写入 redis
中,value
设成一个非法值(比如""
)redis
/ MySQL
之前,都先判定一下 key
是否在布隆过滤器上存在(把所有的 key
都插入到布隆过滤器中) hash+bitmap
,以比较小的空间开销,比较快的时间速度,实现针对 key
是否存在的判定#高频面试
由于在短时间内,redis
上大规模的 key
失效,导致缓存命中率陡然下降,并且 MySQL
的压力迅速上升,甚至直接宕机
redis
直接挂了 redis
宕机/ redis
集群模式下,大量节点宕机redis
好着呢,但是可能之前短时间内设置了很多 key
给 redis
,并且设置的过期时间是相同的 redis
里设置 key
作为缓存的时候,有的时候为了考虑缓存的时效性,就会设置过期时间(和 redis
内存淘汰机制,是配合使用的)如何解决?
redis
集群可用性的保证key
设置过期时间/过期时间的时候添加随机的因子(避免同一时刻过期)#高频面试
相当于缓存雪崩的特殊情况。针对热点 key
,突然过期了,导致大量的请求直接访问到数据库上,甚至引起数据库宕机
key
访问频率高,影响更大如何解决?
key
,并设置永不过期 redis
作为缓存redis
内存淘汰机制