深入学习 Redis - 如何使用 Redis 作缓存?缓存更新策略?使用需要留意哪些
目录一、Redis 作为缓存
1.1、缓存的基本概念
1.1.1、理解
1.1.2、缓存存什么样的数据?二八定律
1.2、如何使用 redis 作为缓存
1.3、缓存更新策略(redis 内存镌汰机制 / 重点)
1.3.1、定期天生
1.3.2、实时天生
内存镌汰策略(经典面试)
1. FIFO (First In First Out) :先进先出
2. LRU (Least Recently Used) :镌汰最久未使⽤的
3. LFU (Least Frequently Used) :镌汰访问次数最少的
4. Random 随机镌汰
深入理解镌汰策略:
redis 中采用的镌汰策略
1.3.3、redis 内存镌汰策略的特性
1.4、缓存使用的留意事项(重点)
1.4.1、缓存预热(Cache preheating)
1.4.2、缓存穿透(Cache penetration)
1.4.3、缓存雪崩(Cache avalanche)
1.4.4、缓存击穿(Cache breakdown)
1.4.5、缓存和数据库数据同步题目
1.4.6、缓存同等性办理方案(集群多实例并发读写导致不同等)
一、Redis 作为缓存
1.1、缓存的基本概念
1.1.1、理解
缓存可以理解为,将常用的数据从放到一个访问速率更快的的地方,方便更快的随时读取.
也就是说,速率快的装备,可以作为速率慢的装备的缓存,加快读取速率。在计算机硬件中的访问速率如下:
[*]CPU 寄存器 > 内存 > 硬盘 > 网络
最常见的就是,使用 内存 作为 硬盘 的缓存,比如 redis.....
固然 硬盘 也可以作为 网络 的缓存,比如浏览器通过 http/https 从服务器上获取数据(html、css、js、图片、视频......)并举行展示,像这样体积大,但又不常常改变的数据,就可以保存到浏览器当地硬盘上,后续在打开这个页面,就不必重新从网络获取上述数据了.
1.1.2、缓存存什么样的数据?二八定律
固然是热门数据~
缓存速率虽然快,但是空间小,因此大部分情况,缓存只存放一些热门数据,就非常有效了.
这里就不得不提一下二八定律了,就是说缓存 只需要存储 20% 的热门数据,就可以应对 80% 的请求.
具体一点来讲~
[*]即时性、数据同等性要求不高:引入缓存就会引入同等性题目,因为我们一般都会先去缓存上去读取数据,如果缓存上没有才去数据库中读. 这就导致一旦数据库中的数据发生变化,需要通过 异步/同步 的方式(具体要看业务要求强同等,还是终极同等)来更新缓存上是数据. 如果是异步更新缓存,就可能出现短暂的不同等现象.
[*]访问量大,并且更新频率不高的数据(读多写少):更新频率高的数据为了包管数据同等性,会带来更大开销.
比方,电商体系中,商品分类,商品列表....... 都适合缓存并设置一个过期时间(根据数据更新频率而定). 比如后台发布一个商品,买家需要 5 分钟才能看到一个商品一般还是可以接受的.
1.2、如何使用 redis 作为缓存
我们通常使用 redis 作为 数据库(mysql)的缓存.
这是由于,数据库是非常紧张的组件,但是速率又很慢,一旦短时间内有大量请求来临,就有可能使数据库压力过大,导致宕机.
为什么会压力过大,导致宕机?
服务器每次处理一个请求,都要消耗一些硬件资源(cpu、内存、硬盘、网络......),任何一种资源的消耗超出了机器提供的上限,就很容易出现故障了.
如何进步 mysql 能承担的并发量?
1. 开源:引入更多的机器,构成数据库集群,比方 主从复制(纵然主节点宕机,也可以通过提升从节点为主节点来办理)、分库分表.....
2. 节省:引入缓存,就是范例的方案. 把一些频繁的读取的热门数据保存到缓存上,后续再查询数据的时候,如果缓存已经存在了,就直接把从缓存上读到的数据返回,也就不在访问 mysql 了.
https://img-blog.csdnimg.cn/d056707ee89a4f6cbd182a27ff96d3e8.png
1.3、缓存更新策略(redis 内存镌汰机制 / 重点)
现实的工作中,如何知道 redis 中应该存储哪些数据?如何知道哪些数据使热门数据?
这就得看你使用缓存的哪种更新策略了~
1.3.1、定期天生
每隔⼀定的周期 (比如⼀天/⼀周/⼀个⽉) , 对于访问的数据频次进⾏统计,并以日志的形式记录下来,末了挑选出访问频次最⾼的前 N% 的数据,放到缓存中.
比方搜索引擎.
搜索引擎的 “查询词” 就是要关注的 “访问的数据”,通过日志,把天天(也可以按一周、一月)都使用到了哪些词,给记录下来,就可以针对这些日志举行统计(这里的统计数据量非常大,需要写个步伐来统计,数量大到可能需要使用分布式体系来存储日志 HDFS),统计这一天中,每个词出现的频率,再根据频率降序排序,提取出 前 20% 的词,就可以以为这些词是 “热门词” .
接下来就可以把这些热门词,以及涉及到的搜索结构都提前拎出来,放到类似 “ redis” 这样的缓存中了。
如何定期统计呢?
可以写一套离线流程(往往使用 shell,python 写脚本代码),然后通过 定时任务 来触发(一天更新一次、一个月更新一次......),具体的:
a)完成统计热词的过程.
b)根据热词,找到搜索结果的数据.
c)把得到缓存数据同步到缓存服务器上.
d)控制这些缓存服务器自动重启.
定期天生的优缺点
长处:实现起来比力简单,过程可控(缓存中有什么东西,是比力固定的),方便排查题目.
缺点:实时性不够,如果出现一些突发性的变乱,出现了一些新的热门词,新的热词就可能对数据库带来较大的压力(缓存中查询没有,直接打到数据库),比方,过年的前几天,“春节晚会” 这个词就会变的特别高频、大概是某个突发的消息......
1.3.2、实时天生
先给缓存设定容量上限(可以通过 Redis 设置⽂件的 maxmemory 参数设定).
接着,之后用户每次查询:
[*]如果在 Redis 中查到了,就直接返回.
[*]如果 Redis 中没有,就从数据库查询,在把查到的结果写入 Redis.
颠末一段时间的 “动态平衡” ,redis 中的 key 就逐渐变成了 热门数据.
题目1:maxmemory 设置成多少合适?(以下来自于文心一言的建议)
[*] 小型项目:
[*]对于内存需求较小的小型项目,通常可以将maxmemory设置为较低的值,比方100MB到500MB。这样的设置可以满足基本的缓存和存储需求,同时不会消耗过多的体系资源。
[*] 中型项目:
[*]对于中型项目,可能需要处理更多的数据和请求,因此建议将maxmemory设置在500MB到2GB之间。这个范围可以提供充足的内存来支持更复杂的操纵和数据存储。
[*] 大型项目:
[*]对于大型项目,可能需要处理大量的数据和高并发的请求。在这种情况下,建议将maxmemory设置在2GB以上,甚至可以到达数十GB或更多。这样可以确保Redis能够有充足的内存来处理大量的数据和请求。
需要留意的是,maxmemory的设置应该根据项目的现实需求和可用体系资源来确定。在设置maxmemory时,还需要思量Redis的持久化策略、数据镌汰策略以及内存交换等因素。同时,还需要监控Redis的内存使用情况,以便根据现实需求举行调整和优化。
别的,如果开启了Redis的快照功能(RDB或AOF),maxmemory的设置还需要思量快照文件的大小和频率。为了确保体系的稳定性和性能,建议将maxmemory设置为物理内存的45%(如果开启了快照功能)或体系可用内存的95%(如果没有开启快照功能)。
题目2:但是这样不绝的写,redis 中的数据就会越来越多,到达 redis 设置的容量上限之后怎么办?
内存镌汰策略(经典面试)
为了办理上述题目,就可以使用以下四种 “内存镌汰策略” (以下镌汰策略不局限于 redis):
1. FIFO (First In First Out) :先进先出
把缓存中存在时间最久的 (也就是先来的数据) 镌汰掉.
2. LRU (Least Recently Used) :镌汰最久未使⽤的
记录每个 key 的最近访问时间. 把最近访问时间最⽼的 key 镌汰掉.
3. LFU (Least Frequently Used) :镌汰访问次数最少的
记录每个 key 最近⼀段时间的访问次数. 把访问次数最少的镌汰掉
4. Random 随机镌汰
从所有的 key 中抽取荣幸儿被随机镌汰掉
深入理解镌汰策略:
如果在 甄嬛传 中,你是谁人皇上,后宫佳丽三千,但现实上,你能宠幸的妃子也就那么几个(精神有限),相当于热门数据.
本日选秀一批新的小主,而你看上了其中的一个,那么就意味着后宫必有人失宠,那么到底要冷落谁呢?
FIFO:皇后最老,先冷落了.
LRU:找个宦官统计最近的宠幸时间,比如,皇后(10天前)、华妃(一个月前)、熹妃(一天前),那么华妃失宠.
LFU:找个宦官统计最近的宠幸次数,比如,皇后(6次)、华妃(1次)、熹妃(10次),那么华妃失宠.
Random:随机冷落一个妃子.
redis 中采用的镌汰策略
[*]volatile-ttl(相当于 FIFO, 只不过是局限于过期的 key) 在设置了过期时间的key中,根据过期时间举行镌汰,越早过期的优先被镌汰.
[*]volatile-lru(就是 LRU,只不过局限于过期的 key) 当内存不足以容纳新写⼊数据时,从设置了过期时间的key中使⽤LRU(最近最少使用)算法举行镌汰.
[*]allkeys-lru(就是 LRU,针对所有 key) 当内存不⾜以容纳新写⼊数据时,从所有key中使⽤LRU(最近最少使用)算法举行镌汰
[*]volatile-lfu(就是 LFU,只不过局限于过期的 key) 4.0版本新增,当内存不⾜以容纳新写⼊数据时,在过期的key中,使⽤LFU算法 举行删除key.
[*]allkeys-lfu(就是 LFU,针对所有 key) 4.0版本新增,当内存不⾜以容纳新写⼊数据时,从所有key中使⽤LFU算法举行镌汰.
[*]volatile-random 当内存不⾜以容纳新写⼊数据时,从设置了过期时间的key中,随机镌汰数据.
[*]allkeys-random 当内存不⾜以容纳新写⼊数据时,从所有key中随机镌汰数据.
[*]noeviction 默认策略,当内存不⾜以容纳新写⼊数据时,新写⼊操纵会报错.
1.3.3、redis 内存镌汰策略的特性
题目:假设有一天触发了内存镌汰机制,如今体系判断需要删除一个 set,那么到底是删除这整个 set 呢?还是删除这个 set 中的某些成员?
这里我们需要清除一点:Redis 不会单独去删除一个 set 数据结构中的部分成员来释放内存,而是直接删除整个 key-value 对。
如果你的 Redis 中存储了一个 set 数据结构,并且这个 key 被镌汰策略选中,那么整个 set(包括它的所有成员)都会被删除,而不是只删除 set 中的某些成员。
1.4、缓存使用的留意事项(重点)
1.4.1、缓存预热(Cache preheating)
这里紧张针对缓存更新策略是 实时天生的(定期天生 不涉及 “预热” ).
为什么要预热?
redis 服务器初次接入之后,服务器是没有数据的,此时所有请求都会直接打给 mysql,在 redis 上没查到,而在 mysql 上查到的数据会继续写入 redis,随着时间推移,redis 上的数据越积累越多 mysql 承担的压力才逐渐变小 .
那么没预热前,mysql 的压力是相当大的.
如何办理上述题目?
通过缓存预热,就可以办理. 紧张就是,把缓存 定期天生 和 实时天生 联合一下.
具体的,先通过离线的方式,通过一些统计途径,统计一些热门数据,导入到 redis 中,此时导入的这批热门数据,就能帮 mysql 承担很大压力了.
随着时间的推移,逐渐就使用新的热门数据镌汰旧数据了.
1.4.2、缓存穿透(Cache penetration)
查询某个 key ,在 redis 中没有,mysql 中也没有,这个 key 也就不会更新到 redis 中。
这就导致,这次查询没有,下次查,还是没有....... 如果这样的数据很多,并且反复查询,一样会给 mysql 带来很大压力.
如那边理?
首先是一种亡羊补牢的方式:通过改进业务/加强监控警报,但这都是出现变乱,才采取的行为.
更靠谱的方案(降低题目的严肃性):
1. 如果这个 key 在 redis 和 mysql 上都不存在,仍然把这个 key 写入 redis,value 设置成一个非法值,比如 "".
2. 引入布隆过滤器. 每次查询 redis / mysql 之前都先判断一下 key 是否在 布隆过滤器 上存在(布隆过滤器本质上是联合 hash + bitmap 实现的,以比力小的空间开销和比力快的速率,针对 key 是否存在举行判断),不存在就没须要查了.
1.4.3、缓存雪崩(Cache avalanche)
在短时间内,redis 中大规模的 key 失效,导致缓存命中率陡然下降,并且 mysql 的压力敏捷上升,甚至直接宕机.
redis 上为什么会出现 大规模的 key 失效?
1. redis 直接挂了,比如 redis 宕机,大概 redis 集群模式下大量节点宕机.
2. redis 好着呢,但是可能之前短时间内设置了很多雷同过期时间的 key.
如那边理?
1) 加强监控警报,比方采取集群的监控,大概哨兵监控的方式,加强 redis 集群可用性.
2)不给 key 设置过期时间,大概设置过期时间的时候,添加一些随机因子,来避免同时过期.
Ps:关于在给 key 设置过期时间时添加随机因子,可能会弄巧成拙,因为我们在给 缓存数据设置过期时间的时候,我们自身所处的时间就是一个不绝变化的~ 有一种情况就是可能在不绝变化的时间里,我们添加了随机因子,反而让大多数 key 的过期时间都同等了.
1.4.4、缓存击穿(Cache breakdown)
这里翻译成 “击穿” 现实上不太合适,以至于一些面试官也分不清击穿和穿透(这种情况,最好两种都说明一下).
这里更适合的翻译成 “瘫痪”.
缓存击穿 相当于 雪崩 的特殊情况. 针对热门 key,如果过期了,导致大量请求直接访问到数据库上,甚至引起数据库宕机.
如那边理?
1. 基于统计的方式发现热门 key,设置为永不过期. 这种方式往往需要服务器结构做出比力大的调整.
2. 举行须要的服务降级(比方服务器的功能原来有 10 个,特定情况下,会关闭一些不紧张的功能,只保留核心功能. 类似于手机的省电模式),比方访问数据库的时候使用分布式锁,限制数据库的访问频率.
1.4.5、缓存和数据库数据同步题目
a)题目描述:
引入缓存就会引入和数据库中数据的同等性题目. 比方缓存和数据库中都保存了商品信息,但是数据库中的商品数据被修改了,那么缓存上的数据也应该被更新,否则就会导致用户下次访问的时候还是读取的缓存上的旧数据.
b)题目办理:
[*]同等性/时效性 要求低的场景:失效模式 大概 异步更新缓存数据.
[*]具体做法:
[*]失效模式:数据库中数据被修改后,可以直接删除之前缓存的旧数据,比及下一次再查询到这个数据的时候主动更新.
[*]异步更新:数据库中数据被修改后,可以通过 mq 大概 起一个线程 来异步的将数据更新到缓存上.
[*]缺点:时效性低(包管终极同等性).
[*]长处:效率高
[*]同等性/时效性 要求高的场景:同步更新缓存数据.
[*]具体做法:数据库中数据被修改后,直接操纵 Redis 更新缓存即可.
[*]缺点:效率低(还需要同步更新缓存).
[*]长处:时效性高,强同等性.
1.4.6、缓存同等性办理方案(集群多实例并发读写导致不同等)
a)题目描述:
对于 1.4.5 所述,无论是双写模式还是失效模式,都可能存在多个实例并发读写导致缓存不同等的题目~
[*]双写模式:比方有 实例A 和 实例B 同时对同一数据举行双写操纵(数据库 + 缓存),但是由于 实例A 在写数据库的时候花费的时间比力长,而此时 实例B 已经双写完成,之后 实例A 才去更新 缓存. 此时,就相当于 实例B 之前写的数据无效.
[*]失效模式:比方有 实例A 对数据举行失效模式,但是在写数据库的时候花费的时间比力长,还没来得及删除缓存,此时有一个 实例B 对同一数据举行读取,发现缓存上有,就把这个 实例A 即将要删除的缓存数据读到了.
b)办理方案:
[*]如果是用户维度数据(比方订单、用户信息),这种并发几率很小的,不消思量这个题目,缓存数据加上过期时间,每隔一段时间触发主动更新即可(无论是双写还是失效模式). 现实上,大多数业务都可以直接通过 缓存 + 过期时间 来办理.
[*]如果是菜单,商品等基础数据,也可以通过 canal 订阅 blnlog 的方式.
[*]同等性要求特别高的数据,可以通过 分布式读写锁 来包管 写操纵之间的安全题目(如果业务不关心脏数据,答应暂时脏数据可忽略).
c)紧张遵循思想:
[*]能放入缓存的数据原来就不应该是实时性,同等性要求特别高的数据,因此大多数场景通过 缓存 + 过期时间 的方式就可以.
[*] 不应该过分设计,增加体系复杂度.
[*]如果遇到实时性,同等性要求特别高的数据,就应该直接查数据库,纵然慢点.
https://img-blog.csdnimg.cn/ce2804b2507d4e22aeb5e988da906dfd.gif
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]