Redis 典型应用之缓存

news2024/11/26 11:03:24

目录

1. 缓存的基本概念

2. 使用 Redis 作为缓存

3. 缓存的更新策略

3.1 定期生成

3.2 实时生成

3.2.1 内存淘汰策略

1. FIFO (First In First Out) 先进先出

2. LRU (Least Recently Used) 淘汰最久未使使用的

3. LFU (Least Frequently Used) 淘汰访问次数最少的

4. Random 随机淘汰

4. 缓存使用的注意事项

1. 缓存预热 (Cache preheating)

2. 缓存穿透 (Cache penetration)

3. 缓存雪崩 (Cache avalanche)

4. 缓存击穿 (Cache breakdown)


1. 缓存的基本概念

Redis 最主要的用途:

1. 存储数据(内存数据库)

2. 缓存 [redis 最常用的场景]

3. 消息队列

缓存是计算机中的一个经典概念,在很多场景都会运用到。

核心思路就是将一些常用数据放到访问速度更快(跟原来相比)的地方,方便随时读取。

对于硬件的访问速度来说,通常是:CPU 寄存器 > 内存 > 硬盘 > 网络

速度快的可以作为速度慢的设备的缓存。

其中最常见的是 内存 作为 硬盘 的缓存。(redis 定位)

硬盘也可以作为网络的缓存(浏览器缓存),像体积大又不太改变的数据(图片,视频,音频,字体)就可以保存到浏览器本体(浏览器所在主机的硬盘上),后续再打开这个页面,就不用重新从网络上获取上述数据了。

缓存速度虽然快,但是空间小。一般在通常情况下,20% 热点数据,可以应对 80% 的请求。

2. 使用 Redis 作为缓存

通常是使用 redis 作为关系型数据库的缓存 (比如 mysql)。

因为在绝大部分商业项目中都会涉及到关系型数据库,虽然关系型数据库功能强大,但是性能不高,那么此时就可以使用 redis 作为缓存。

为什么说关系型数据库性能不高?
1. 数据库把数据存储在硬盘上, 硬盘的 IO 速度并不快. 尤其是随机访问.
2. 如果查询不能命中索引, 就需要进行表的遍历, 这就会大大增加硬盘 IO 次数.
3. 关系型数据库对于 SQL 的执行会做一系列的解析, 校验, 优化工作.
4. 如果是一些复杂查询, 比如联合查询, 需要进行笛卡尔积操作, 效率更是降低很多.

因为 mysql 等数据库,效率比较低,所以承担的并发量就有限。一旦请求数量多了,数据库的压力就会很大,甚至很容易就宕机了。

那么该如何提高 mysql 承担的并发量?

1. 开源:引入更多的机器,构成数据库集群。

2. 节流:引入缓存,就是典型的方案。把一些频繁读取的热点数据保存到缓存上,后续在查询数据的时候,如果缓存中已经存在,那就不再访问 mysql 了。

缓存是用来加快 "读操作" 的速度的. 如果是 "写操作", 还是要老老实实写数据库, 缓存并不能提高性能。

3. 缓存的更新策略

将热点数据存入 redis 中,那么怎么知道哪些数据才是 "热点数据" 呢?

有两种方法,第一种是定期生成,第二种是实时生成。

3.1 定期生成

把会访问的数据,通过日志的方式记录下来。

每隔一定的周期(比如一天/一周/一月),对于访问的数据的频次进行统计。挑选出访问频次最高的前 N% 的数据。

优点:上述过程,实际上实现起来是比较简单的,过程更可控。(缓存中有啥内容是固定的),方便排查问题。

缺点:实时性不够,如果出现一些突发性事件,有一些本来不是热词的内容,成了热词了,新的热词就可能给后面的数据库带来较大的压力。

3.2 实时生成

先给缓存设定容量上限(可以通过 Redis 配置⽂件的 maxmemory 参数设定)。

接下来用户的每次查询:

如果在 redis 查到了,就直接返回。

如果没在 redis 里查到,那就去数据库里查,同时把查询结果写入到 redis 中。

这样不停的写,就会使 redis 的内存占用越来越多,逐渐达到内存的上限。

此时如果再继续往里插入数据,就会出现问题,为了解决上述情况,redis 引入了 "内存淘汰策略"。

3.2.1 内存淘汰策略

通用的淘汰策略主要有以下几种:

1. FIFO (First In First Out) 先进先出

把缓存中存在时间最久的(也就是先来的数据) 淘汰掉。

2. LRU (Least Recently Used) 淘汰最久未使使用的

记录每个 key 的最近访问时间,把最近访问时间最老的 key 淘汰掉。

3. LFU (Least Frequently Used) 淘汰访问次数最少的

记录每个 key 最近一段时间的访问次数,把访问次数最少的淘汰掉。

4. Random 随机淘汰

从所有的 key 中抽取幸运儿被随机淘汰掉。

举个例子,假设你只有一部手机,手机里安装了一些游戏,你经常玩的游戏就那几个:雀魂,崩坏:星穹铁道,明日方舟,phigros,王者荣耀,闪耀暖暖

手机里所有的游戏,就相当于数据库中的全量数据,经常玩的游戏相当于热点数据,存放在缓存中。

某一天,你想玩一个新的游戏,但是你手机内存不够,此时就需要卸载一个游戏,那该卸载哪一个呢?

FIFO:王者荣耀是最先下载的,所以先删除王者荣耀。

LRU:统计最近游玩时间。雀魂(一月前),崩坏:星穹铁道(昨天),phigros(一周前),明日方舟(三天前),王者荣耀(两天前),闪耀暖暖(两周前)。卸载雀魂。

LFU:统计最近一个月的游玩次数。雀魂(3次),崩坏:星穹铁道(25次),phigros(10次),明日方舟(20次),王者荣耀(30次),闪耀暖暖(1次)。卸载闪耀暖暖。

Random:随机挑选一个游戏删除。

这里的淘汰策略, 我们可以自己实现. 当然 Redis 也提供了内置的淘汰策略, 也可以供我们直接使用。

Redis 内置的淘汰策略如下: 

带有 volatile 的就是从设置了过期时间的 key 里删除(设置了过期时间就算,包括过期时间还没到的)

带有 allkeys 的就是从所有的 key 里删除。

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)

noeviction

默认策略,当内存不足以容纳新写入数据时,新写入操作会报错。

4. 缓存使用的注意事项

1. 缓存预热 (Cache preheating)

缓存中的数据:

1. 定期生成 (这种情况,不涉及"预热")

2. 实时生成

redis 服务器首次接入,服务器里是没有数据的,此时,所有的请求都会打给 mysql,随着时间的推移,redis 上的数据越积累越多,mysql 承担的压力就逐渐减小了。

缓存预热,就是用来解决上述问题的。把定期生成和实时生成结合一下。

先通过离线的方式,通过一些统计的途径,先把热点数据找到一批,导入到 redis 中,此时导入的这批热点数据,就能帮 mysql 承担很大的压力了。随着时间的推移,逐渐就使用新的热点数据淘汰掉旧的数据。

2. 缓存穿透 (Cache penetration)

如果访问的 key 在 redis 和 mysql 都不存在,那么这样的 key 不会被放到缓存上,后续仍然在访问该 key,就依然会访问到数据库。

像这样的数据存在很多,并且还反复查询,一样也会给 mysql 带来很大的压力。

产生的原因:

1. 业务设计不合理,比如缺少必要的参数校验环节,导致非法的 key 也被进行查询了(典型)

2. 开发/运维误操作,不小心把部分数据从数据库中误删了

3. 黑客恶意攻击(比较少见)

如何解决?

通过改进业务/加强监控报警。

更靠谱的方案(降低问题严重性):

1. 如果发现这个 key,在 redis 和 mysql 中都不存在,仍然写入 redis 中,value 设成一个非法值(比如 "")

2. 还可以引入布隆过滤器,每次查询 redis / mysql 之前都先判定一下 key 是否在布隆过滤器上存在。(把所有 key 插入到布隆过滤器中)

3. 缓存雪崩 (Cache avalanche)

短时间内,redis 上大规模的 key 失效,导致缓存命中率陡然下降,并且 mysql 的压力迅速上升,甚至直接宕机。

产生原因:

1. redis 直接挂了

2. redis 好着呢,但是可能之前短时间内设置了很多 key 给 redis,并且设置的过期时间是相同的。

给 redis 里设置 key 作为缓存的时候,有的时候为了考虑缓存的时效性,就会设置过期时间。(和 redis 内存淘汰机制,配合使用)

解决方案:

1. 加强监控报警,加强 redis 集群可用性的保证。

2. 不给 key 设置过期时间,设置过期时间的时候添加随机的因子(避免同一时刻过期)

4. 缓存击穿 (Cache breakdown)

相当于缓存雪崩的一种特殊情况,针对热点 key, 突然过期了,导致大量的请求直接访问到数据库上,甚至引起数据库宕机。

解决方案:

1. 基于统计的方式发现热点 key,并设置永不过期。

2. 进行必要的服务降级,例如访问数据库的时候,使用分布式锁,限制同时请求数据库的并发数。

本身服务器的功能有十个,但是在特定情况下,适当的关闭一些不重要的功能,只保留核心功能(服务降级),类似于省电模式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2211579.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用C++编写信息管理系统(歌单信息管理)

C语言是面向过程的编程语言,而C是面向对象的编程语言,在书写代码时风格有所不同(也存在很多共性)。 程序说明 本次系统程序使用的是C语言进行编写,主要考虑怎么实现面向对象的问题。 因为本次程序属于小型系统程序&…

【C++学习】核心编程之类和对象(上)黑马学习笔记—超详细

目录 (一)封装 1.1 封装的意义: 意义一:在设计类的时候,属性和行为写在一起,表现事物 意义二:类在设计时,可以把属性和行为放在不同的权限下,加以控制 1.2 struct和…

【vue】组件及组件化+组件⽣命周期

代码获取 04-组件及组件化组件⽣命周期 ⼀、组件及组件化 1. 为什么需要组件&#xff1f; 1.1 思考 以可折叠⾯板为例, 现要展⽰3个, 如何操作? 可折叠⾯板案例的代码 &#xff1a; <script setup> import { ref } from vue const visible ref(false) </scri…

Day14

std::string的底层实现 三种方式&#xff1a; 深拷贝 写时复制 短字符串优化 深拷贝 无论什么情况&#xff0c;都是采用拷贝字符串内容的方式解决。不需要改变字符串内容时&#xff0c;对字符串进行频繁复制。 用一个string对象初始化另一个string对象时&#xff0c;源对…

MySQL SELECT 查询(三):查询常用函数大全

MySQL SELECT 查询&#xff08;三&#xff09;&#xff1a;查询常用函数大全 1. 单行函数 单行函数是 SQL 中一类重要的函数&#xff0c;它们可以对单行数据进行处理&#xff0c;并返回单个结果。单行函数可以嵌套使用&#xff0c;并提供灵活的数据处理能力。 1.1 定义 只对单…

微知-Mellanox网卡如何导出firmware中的config文件以及文件中有些什么?(ini配置文件,8个区)

背景 Mellanox网卡早期版本以及Engineer simple的DPU支持导出配置文件&#xff0c;该配置文件就是用来告诉firmware的行为。但不是mlxconfig真正设置的文件(mlxconfig -d xxx -e -q应该就是把这个文件读取出来&#xff0c;并且有3个文件&#xff0c;包括默认的&#xff0c;当前…

攻防世界2

forgot 发现是32位文件 fgets(s, 32, stdin)限制读入32位字符&#xff0c;无法利用 __isoc99_scanf("%s", v2) 典型的栈溢出 发现cat flag 覆盖v2-v3&#xff0c;覆盖为cat flag的函数地址 exp&#xff1a; from pwn import * context(oslinux,archamd64,log_lev…

芋道快速开发平台学习笔记

1.接口文档配置 基础知识:SpringDoc注解的使用,它是基于OpenAPI 3和Swagger 3的现代化解决方案,相较于旧版的Swagger2即SpringFox,SpringDoc提供了更简洁、更直观的注解方式。 详见springboot集成springdoc-openapi(模拟前端请求)_springdoc-openapi-ui-CSDN博客 doc文档配置…

c++面向对象三大特性——多态详解与虚函数,虚函数底层

目录 前言&#xff1a; 1. 多态的概念 1.1 概念 2. 多态的定义及实现 2.1多态的构成条件 2.2 虚函数 2.3虚函数的重写 2.4 C11 override 和 final 2.5 重载、覆盖(重写)、隐藏(重定义)的对比 3. 抽象类 3.1 概念 3.2 接口继承和实现继承 4.多态的原理 4.1虚函数表 …

7.1-I2C的中断

I2C的中断与DMA 回顾 HAL_I2C_MASTER_Transmit(&hi2c1,ADRESS,PDate,Size,Time);HAL_I2C_MASTER_Receive(&hi2c1,ADRESS,PDate,Size,Time);通信具体过程如下&#xff1a; 在I2C的轮询模式中 发送时&#xff1a;CPU将以主机0x70 发送 从机 ACK 回复 主机0xAC发送 A…

⽂件的操作

1. 为什么使⽤⽂件&#xff1f; 如果没有⽂件&#xff0c;我们写的程序的数据是存储在电脑的内存中&#xff0c;如果程序退出&#xff0c;内存回收&#xff0c;数据就丢失了&#xff0c;等再次运⾏程序&#xff0c;是看不到上次程序的数据的&#xff0c;如果要将数据进⾏持久化…

深圳大学-Java程序设计-必实验2 类的高级应用

实验目的与要求&#xff1a; 实验目的&#xff1a;熟悉面向对象编程中类的编写。 实验要求&#xff1a; (1).请自行选择2023年成都大运会或2023杭州亚运会。大型运动会通常包括众多比赛项目。请通过分析&#xff0c;抽象它们所共有的性质&#xff0c;定义一个关于比赛项目的抽…

点评项目-6-缓存更新策略、缓存穿透、雪崩

缓存更新策略 使用 redis 缓存记录的信息&#xff0c;有可能在数据库被信息被修改导致信息不一致&#xff0c;使用缓存更新来解决这个问题 缓存更新策略主要有三种&#xff1a; 1.内存淘汰(redis默认开启) 2.超时剔除(给key添加TTL时间) 3.主动更新(编写业务逻辑) 主动更新策…

网络通信与并发编程(一)网络通信、osi五层模型、tcp协议的三次握手与四次挥手

网络通信、osi五层模型、tcp协议的三次握手与四次挥手 文章目录 网络通信、osi五层模型、tcp协议的三次握手与四次挥手一、网络通信二、osi五层模型1.物理层2.数据链路层3.网络层4.传输层5.应用层 三、tcp协议的三次握手与四次挥手 一、网络通信 网络通信是指在网络中的两个或…

Java ==> 数组(入门)

文章目录 前言一、一维数组1.入门操作2.何为null&#xff1f;3.数组可以作为函数的参数4.数组可以作为函数的返回值 二、二维数组1.基础操作2.不规则的二维数组 总结 前言 在Java语言当中&#xff0c;数组是一种基本的数据结构&#xff0c;它存储了固定大小的同类型元素的集合…

告别卡顿!五款Windows录屏工具,让每一帧都清晰流畅

小伙伴们&#xff0c;是不是在寻找一款好用、实用的Windows录屏工具呢&#xff1f;别担心&#xff0c;这次我给大家带来了一款热门录屏工具的详细评测和使用感受&#xff0c;包括福昕录屏、转转录屏、爱拍录屏、OBS录屏和EV录屏。快来看看哪款最适合你吧&#xff01; 一、福昕录…

反射的学习

1、什么是反射 反射允许对封装类的字段&#xff0c;方法和构造函数的信息进行编程访问。 也就是&#xff1a; 反射允许对成员变量&#xff0c;成员方法和构造方法的信息进行编程访问。 2、获取class对象 获取一个类的字节码文件对象&#xff1a; 方式1&#xff1a;Class.…

linux 环境运行 jenkins.war包,有可能会出现字体问题,jdk版本:11 jenkins 版本:2.420

jenkins的目录&#xff1a; /usr/jenkins 启动命令 java -Djava.awt.headlesstrue sudo timedatectl set-timezone Asia/Shanghai-Xmx1024m -jar jenkins.war --httpPort8090 任意目录启动&#xff1a; nohup java -Djava.awt.headlesstrue -Xms1024m -Xmx1024m -jar /usr/j…

基于opencv答题卡识别判卷

我们是一个深度学习领域的独立工作室。团队成员有&#xff1a;中科大硕士、纽约大学硕士、浙江大学硕士、华东理工博士等&#xff0c;曾在腾讯、百度、德勤等担任算法工程师/产品经理。全网20多万粉丝&#xff0c;拥有2篇国家级人工智能发明专利。 社区特色&#xff1a;深度实…

Excel使用技巧:数据-》分列:处理log数据,把有用的信息提取出来;查找Ctrl+F,替换Ctrl+H;通配符

Excel的正确用法&#xff1a; Excel是个数据库&#xff0c;不要随意合并单元格。 数据输入的时候一定要按照行列输入&#xff0c;中间不要留空&#xff0c;不然就没有关联。 数据-》分列&#xff1a;处理log数据&#xff0c;把有用的信息提取出来。 按照向导一步一步操作。…