【Redis】缓存预热、雪崩、击穿、穿透、过期删除策略、内存淘汰策略
Redis常见问题总结:
- Redis常见问题总结
- Redis缓存预热
- Redis缓存雪崩
- Redis缓存击穿
- Redis缓存穿透
- Redis 中 key 的过期删除策略
- 数据删除策略
- Redis内存淘汰策略
- 一、Redis对过期数据的处理
- (一)相关配置
- (二)内存淘汰流程
- (三)动态改配置命令
- 二、内存淘汰策略的种类及特点
- (一)Redis 4.0以前的策略
- (二)Redis 4.0以后增加的策略
- 三、常见的淘汰算法
- (一)FIFO算法(先进先出)
- (二)LRU算法(最近最少使用)
- (三)LFU算法(最不常使用)
- (四)LRU和LFU的选择
- 总结
Redis常见问题总结
Redis缓存预热
“宕机”服务器启动后迅速宕机,指的是服务刚上线由于Redis中没有任何数据,导致大量请求访问数据库,主从之间数据吞吐量较大,数据同步操作频度较高。
而缓存预热解决的就是,在系统启动前,提前将相关的数据直接加载到缓存系统。避免用户在请求的时候,先查询数据库,再将数据库的查询到的数据缓存到Redis的问题。用户可以直接查询事先被预热的缓存数据。
解决方案:
- 准备工作:
- 日常例行统计数据访问记录,统计访问频度较高的热点数据。
- 将统计结果中的数据分类,根据级别,Redis优先加载级别较高的热点数据
- 实施:
- 使用脚本程序固定触发数据预热过程
- 如果条件允许,使用CDN(内容分发网络),效果会更好
Redis缓存雪崩
缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。【这里指的是同一批key的过期时间相同或者Redis服务挂掉】
解决方案:
- 给不同的Key的TTL添加随机值
- 利用Redis集群提高服务的可用性
- 给缓存业务添加降级限流策略
- 给业务添加多级缓存
Redis缓存击穿
缓存击穿问题也叫热点Key问题,就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击
常见的解决方案有两种:
- 互斥锁
- 逻辑过期
互斥锁:
逻辑过期:
Redis缓存穿透
缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库
常见两种解决方案:
- 缓存空对象
- 布隆过滤器
Redis 中 key 的过期删除策略
数据删除策略
什么是过期数据?
Redis是一种内存级数据库,所有数据均存放在内存中,内存中的数据可以通过TTL指令获取其状态
- XX :具有时效性的数据
- -1 :永久有效的数据
- -2 :已经过期的数据或被删除的数据或未定义的数据
注意:过期的数据真的删除了吗?不是的
删除策略比对
1. 定时删除 节约内存,无占用 不分时段占用CPU资源,频度高拿时间换空间
2. 惰性删除 内存占用严重延时执行,CPU利用率高拿空间换时间
3. 定期删除 内存定期随机清理每秒花费固定的CPU资源维护内存随机抽查,重点抽查
Redis的过期键的删除策略是指当Redis中的缓存的key过期了,Redis要如何处理。
Redis中提供了三种删除策略:
1.定时删除
当放入数据后,设置一个定时器,当定时器读秒完毕后,将对应的数据从dict中删除。
优点: 内存友好,数据一旦过期就会被删除
缺点: CPU不友好,定时器耗费CPU资源,并且频繁的执行清理操作也会耗费CPU资源。用时间换空间
2.惰性删除
当数据过期的时候,不做任何操作。当访问数据的时候,查看数据是否过期,如果过期返回null,并且将数据从内存中清除。如果没过期,就直接返回数据。
优点: CPU友好,数据等到过期并且被访问的时候,才会删除。
缺点: 内存不友好,会占用大量内存。用空间换时间
3.定期删除
定期删除是定时删除和惰性删除的折中方案。每隔一段时间对redisServer中的所有redisDb的expires依次进行随机抽取检查。
Redis中有一个server.hz定义了每秒钟执行定期删除的次数,每次执行的时间为250ms/server.hz。Redis中会维护一个current_db变量来标志当前检查的数据库。current_db++,当超过数据库的数量的时候,会重新从0开始。
定期检查就是执行一个循环,循环中的每轮操作会从current_db对应的数据库中随机依次取出w个key,查看其是否过期。如果过期就将其删除, 并且记录删除的key的个数。如果过期的key个数大于w25%,就会继续检查当前数据库,当过期的key小于w25%,会继续检查下一个数据库。当执行时间超过规定的最大执行时间的时候,会退出检查。一次检查中可以检查多个数据库,但是最多检查数量是redisServer中的数据库个数,也就是最多只能从当前位置检查一圈。
Redis内存淘汰策略
一、Redis对过期数据的处理
Redis的内存淘汰机制主要是用于在Redis用于缓存的内存不足时,处理需要新写入且需申请额外空间的数据。
(一)相关配置
- 在
redis.conf
中:- 配置
maxmemory <bytes>
,用于设置Redis的最大内存空间。若不设定该参数,默认无限制,通常会设定为物理内存的四分之三。 - 配置
maxmemory-policy noeviction
,用于设置淘汰策略,默认为noeviction
。
- 配置
(二)内存淘汰流程
- 客户端发起需要申请更多内存的命令(如
set
)。 - Redis检查内存使用情况,若已使用内存大于
maxmemory
,则根据用户配置的不同淘汰策略来淘汰内存(key),以换取一定的内存。 - 若上述步骤均无问题,则该命令执行成功。
(三)动态改配置命令
Redis支持动态改配置,无需重启。
- 设置最大内存:
config set maxmemory 100000
- 设置淘汰策略:
config set maxmemory-policy noeviction
二、内存淘汰策略的种类及特点
(一)Redis 4.0以前的策略
- noeviction:当内存使用超过配置时会返回错误,不会驱逐任何键。(默认选项,一般不选用)
- allkeys-lru:当内存不足以容纳新写入数据时,在整个键空间中,移除最近最少使用的key。(最常用)
- volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。
- allkeys-random:当内存不足以容纳新写入数据时,在整个键空间中,随机移除某个key。
- volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。
- volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。
(二)Redis 4.0以后增加的策略
- volatile-lfu:从所有配置了过期时间的键中驱逐使用频率最少的键。
- allkeys-lfu:从所有键中驱逐使用频率最少的键。
内存淘汰策略可通过配置文件修改,redis.conf
对应的配置项是maxmemory-policy
,修改对应的值即可。
三、常见的淘汰算法
(一)FIFO算法(先进先出)
- 思想
- 基于队列的先进先出原则,最先进入的数据会被最先淘汰掉,是最简单、最公平的思想。
- 实现
- 维护一个FIFO队列,按照时间顺序将各数据(已分配页面)链接起来组成队列,并将置换指针指向队列的队首。进行置换时,把置换指针所指的数据(页面)顺次换出,并把新加入的数据插到队尾即可。
- 缺点
- 会导致缺页率增加。随着分配页面的增加,被置换的内存页面往往是被频繁访问的,因此FIFO算法会使一些页面频繁地被替换和重新申请内存,从而导致缺页率增加。由于缺页率会随着分配页面的增加而增加,使得redis的开销也逐渐增加,所以这种算法已不再使用。
(二)LRU算法(最近最少使用)
- 思想
- 最近最少使用的会被优先淘汰。如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小。当空间满时,最久没有访问的数据最先被淘汰掉。
- 实现
- 用双向链表(LinkedList)+哈希表(HashMap)实现(链表用来表示位置,哈希表用来存储和查找),在Java里有对应的数据结构
LinkedHashMap
。
- 用双向链表(LinkedList)+哈希表(HashMap)实现(链表用来表示位置,哈希表用来存储和查找),在Java里有对应的数据结构
- 缺点
- 在需要淘汰时,只是随机选取有限的key进行对比,排除掉访问时间最久的元素,不能选择整个候选元素的最优解,只是局部最优。默认随机选取的key的数目为5,在配置文件
redis.conf
中由maxmemory_samples
属性的值决定,采样数量越大越接近于标准LRU算法,但也会带来性能的消耗。 - 在Redis 3.0以后增加了LRU淘汰池,进一步提高了与标准LRU算法效果的相似度。淘汰池即维护的一个数组,数组大小等于抽样数量
maxmemory_samples
,在每一次淘汰时,新随机抽取的key和淘汰池中的key进行合并,然后淘汰掉最旧的key,将剩余较旧的前面5个key放入淘汰池中待下一次循环使用。假如maxmemory_samples = 5
,随机抽取5个元素,淘汰池中还有5个元素,相当于变相的maxmemory_samples = 10
,所以进一步提高了与LRU算法的相似度。
- 在需要淘汰时,只是随机选取有限的key进行对比,排除掉访问时间最久的元素,不能选择整个候选元素的最优解,只是局部最优。默认随机选取的key的数目为5,在配置文件
(三)LFU算法(最不常使用)
- 思想
- 如果一个数据在最近一段时间很少被访问到,那么在将来它被访问的可能性也很小。当空间满时,最小频率访问的数据最先被淘汰。
- 实现及问题解决
- 为每个key维护一个计数器,每次key被访问时,计数器增大,计数器越大,则认为访问越频繁。但存在以下问题:
- 可能存在某个key在开始一个小时内有100万的访问量,但之后一小时内访问量为0,而在第二个小时内另一个key的访问量达到20万,此时第二个小时内key1会优先于key2被淘汰,尽管key2在该小时内访问量更大。
- 当新加入的key,由于没有被访问过,初始计数器为0,若此时触发淘汰机制,会把最先添加的key最先淘汰掉。
- 解决方案:在LFU算法中维护了一个24bit的字段,被分成16 bits与8 bits两部分。第一部分(高16 bits)用来记录计数器的上次缩减时间,时间戳,单位精确到分钟。第二部分(低8 bits)用来记录计数器的当前数值,该数值反映访问频率,而非次数。
- 在
redis.conf
配置文件中,lfu-log-factor
用来调整计数器counter的增长速度,lfu-log-factor
越大,counter增长越慢。lfu-decay-time
是一个以分钟为单位的数值,用来调整counter的缩减速度。
- 为每个key维护一个计数器,每次key被访问时,计数器增大,计数器越大,则认为访问越频繁。但存在以下问题:
(四)LRU和LFU的选择
需要根据业务权衡到底是选择淘汰最近最少使用(LRU)还是选择最不经常使用(LFU)。总的来说,无论是LRU、LFU、TTL还是Random都是近似算法来实现的,在可靠性和性能上做了一定的平衡。在业务中应主动删除没有价值的数据,或者更新某些key的过期时间等来提高Redis的性能和空间,不能过分依赖于淘汰策略。
(此处可根据需要插入相关图片,例如LRU和LFU算法的示意图等,假设插入了一张LRU算法的示意图,如下所示)
总结
Redis的内存淘汰策略的选取并不会影响过期的key的处理。内存淘汰策略用于处理内存不足时需要申请额外空间的数据;过期策略用于处理过期的缓存数据。要根据实际业务场景和需求合理选择内存淘汰策略,并结合主动的数据管理操作来优化Redis的性能和内存使用。
相关文章:

【Redis】缓存预热、雪崩、击穿、穿透、过期删除策略、内存淘汰策略
Redis常见问题总结: Redis常见问题总结Redis缓存预热Redis缓存雪崩Redis缓存击穿Redis缓存穿透 Redis 中 key 的过期删除策略数据删除策略 Redis内存淘汰策略一、Redis对过期数据的处理(一)相关配置(二)内存淘汰流程&a…...

【LeetCode】每日一题 2024_10_15 三角形的最大高度(枚举、模拟)
前言 每天和你一起刷 LeetCode 每日一题~ LeetCode 启动! 题目:三角形的最大高度 代码与解题思路 久违的简单题 这道题读完题目其实不难想到有两条路可以走: 1、题目很明显只有两种情况,枚举是第一个球是红球还是蓝球这两种情…...

2024版最新网络安全工程师入门教程(非常详细)从零基础入门到精通,看完这一篇就够了
前言 想要成为网络安全工程师,却苦于没有方向,不知道从何学起的话,下面这篇 网络安全入门 教程可以帮你实现自己的网络安全工程师梦想,如果想学,可以继续看下去,文章有点长,希望你可以耐心看到…...

vue中关于router.beforeEach()的用法
router.beforeEach()是Vue.js中的路由守卫,用于在路由跳转前进行校验、取消、重定向等操作。 基本使用: const router new VueRouter({ ... })router.beforeEach((to, from, next) > {// ... }) to: 即将要进入的目标路由对象 from: 当前导航正要…...

C++模板初阶,只需稍微学习;直接起飞;泛型编程
🤓泛型编程 假设像以前交换两个函数需要,函数写很多个或者要重载很多个;那么有什么办法实现一个通用的函数呢? void Swap(int& x, int& y) {int tmp x;x y;y tmp; } void Swap(double& x, double& y) {doubl…...

【数据结构 | 红黑树】红黑树的性质和插入结点时的调整
文章目录 红黑树红黑树插入时的调整?1. 插入结点是根结点2. 插入结点的叔叔是红色3. 插入结点的叔叔是黑色LL 型RR型LR型RL型 红黑树 前提:二叉搜索树(左 < 根 < 右)—— 左根右根和**叶子(NULL)**都…...

mysql学习教程,从入门到精通,SQL导入数据(44)
1.SQL 导出数据 以下是一个关于如何使用 SQL 导出数据的示例。这个示例将涵盖从一个关系数据库管理系统(如 MySQL)中导出数据到 CSV 文件的基本步骤。 1.1、前提条件 你已经安装并配置好了 MySQL 数据库。你有访问数据库的权限。你知道要导出的表名。…...

【SpringAI】(二)让你的Java程序接入大模型——适合Java宝宝的大模型应用开发
开始之前,如果你对大模型完全没了解过,建议阅读之前的大模型入门文章: 【SpringAI】(一)从实际场景入门大模型——适合Java宝宝的大模型应用开发 那么今天就开始写一个基于Spring AI程序的HelloWord!将大模型接入到咱…...

音频剪辑在线工具 —— 让声音更精彩
你是否曾梦想过拥有自己的声音创作空间,却苦于复杂的音频编辑软件?接下来,让我们一同揭开这些音频剪辑在线工具的神秘面纱,看看它们如何帮助你实现从录音到发布的无缝衔接。 1.福昕音频剪辑 链接直达>>https://www.foxits…...

http短连接和长连接
参考短连接和长连接 短连接:客户端向服务器每进行一次Http操作,都需建立一次连接,任务完成后,断开连接;长连接:建立长连接后,传输数据的连接将不会中断,客户端每次访问服务器时都会…...

日志分析删除
日志分析 场景 运维嫌弃生产环境打印日志过多,而且日志存储需要费用,让我们减少打印日志大小,所以需要分析日志在哪里打印的过多 解决方案 读取生产日志文件,统计分析打印日志的地方,最后删除代码中打印日志的地方…...

DART: Implicit Doppler Tomography for Radar Novel View Synthesis 笔记
Link:https://wiselabcmu.github.io/dart/ Publish: 2024CVPR Abstract DART主要任务就是用来合成雷达距离多普勒图像range-droppler,可用于生成高质量的断层扫描图像。 Related Work 1 Radar Simulation 基于模型的方法 任务ÿ…...

redis-cli执行lua脚本
连接redis服务器命令 redis-cli -h 10.10.xx.xx -p 6380 -a password执行lua脚本传递KEY VALUE redis-cli -h 10.10.xx.xx -p 6380 -a password key1 key2 , arg1 arg2key和参数通过逗号分割,逗号前后必须有一个空格 如下执行lua脚本示例: -- script.…...

MySQL9的3个新特性
【图书推荐】《MySQL 9从入门到性能优化(视频教学版)》-CSDN博客 《MySQL 9从入门到性能优化(视频教学版)(数据库技术丛书)》(王英英)【摘要 书评 试读】- 京东图书 (jd.com) 本文讲解MySQL9的3个新特性&…...

《网络基础之 HTTP 协议:状态码含义全解析》
《网络基础之 HTTP 协议:状态码含义全解析》 在网络通信的浩瀚世界中,HTTP 协议犹如一座坚实的桥梁,连接着客户端与服务器。而其中的状态码,则是这座桥梁上的重要标识,为双方的交互提供了关键的反馈信息。 一、状态码…...

java真的正在越来越失去竞争力了吗
题记: java真的在越来越失去竞争力了吗?最近参加校招面试,过程中有问道java的问题,有的同学很直接了当(或者是不假思索)地说,java已经过时了吧,现在学java的人越来越少了。那么事实…...

【通过zip方式安装mysql服务】
通过zip方式安装mysql服务 Mysql安装包下载mysql安装及环境配置1.解压缩配置环境变量初始化mysql配置安装mysql服务启动MySQL服务连接mysql修改root用户密码 Mysql安装包下载 通过访问mysql官网下载:mysql下载地址 mysql安装及环境配置 1.解压缩 下载完成后&am…...

每日OJ题_WY3小易的升级之路_数学模拟_C++_Java
目录 牛客_WY3小易的升级之路_数学模拟 题目解析 C代码 Java代码 牛客_WY3小易的升级之路_数学模拟 小易的升级之路_牛客题霸_牛客网 (nowcoder.com) 描述: 小易经常沉迷于网络游戏.有一次,他在玩一个打怪升级的游戏,他的角色的初始能力值为 a.在接下来的一段…...

python xml的读取和写入
import xml.etree.ElementTree as ET from xml.dom import minidom# 读取XML文档 tree ET.parse("./xml_3/z_20240827_001.xml") root tree.getroot() # 获取size元素 size_find_0 root.find("size") # 获取width子元素 size_w size_find_0.find("…...

WebGL 小白入门学习
1. WebGL是什么? WebGL(Web Graphics Library)是一种JavaScript API,它允许你在不需要安装任何额外插件的情况下,直接在浏览器中渲染高性能的2D和3D图形。WebGL利用了用户的图形处理单元(GPU)来…...

OSI七层协议
OSI(Open System Interconnection)七层协议,即开放式系统互联参考模型,是一个由国际标准化组织(ISO)提出的用于描述计算机网络中通信的结构和功能的理论模型。它将网络通信过程分为七个层次,每个…...

超平面(Hyperplane)和半空间(Halfspace)
文章目录 一、超平面(Hyperplane)1. 定义2. 超平面的方程3. 例子4. 超平面的性质 二、半空间(Halfspace)1. 定义2. 半空间的表示3. 半空间的性质 三、超平面与半空间的关系四、应用1. 线性规划2. 机器学习3. 计算几何4. 凸分析 五…...

TCP(Transmission Control Protocol,传输控制协议)整理
TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的传输协议,它是OSI(Open System Interconnection,开放式系统互联)模型中的第四层协议,通常使用于网络中的…...

R语言绘制线性回归图
线性回归图以二维坐标系展示两个变量关系。数据点代表实际观测值,核心是线性回归线。此线通过统计方法确定,与数据点距离平方和最小。它反映变量间线性趋势,斜率正负决定相关方向。可用于预测因变量值,也能进行推断统计。在数据分…...

C++进阶:map和set的使用
目录 一.序列式容器和关联式容器 二.set系列的使用 2.1set容器的介绍 2.2set的构造和迭代器 2.3set的增删查 2.4insert和迭代器遍历的样例 2.5find和erase的样例 编辑 2.6multiset和set的差异 2.7简单用set解决两道题 两个数组的交集 环形链表二 三.map系列的使用…...

深入理解C++ STL中的 vector
文章目录 1. vector 的概述1.1 vector 是什么?1.2 vector 的优点1.3 vector 的缺点 2. vector 的基本使用2.1 vector 的定义2.2 基本操作2.3 示例2.4 迭代器的使用 3. vector 的内部实现原理3.1 动态数组的实现3.2 内存管理3.3 内存扩展策略3.4 元素的插入与删除3.4…...

MySQL 安装与配置详细教程
MySQL 安装与配置详细教程 MySQL 是一款流行的关系型数据库管理系统,广泛应用于 Web 应用和应用程序中。在本文中,我们将提供一份详细的 MySQL 安装与配置教程,帮助初学者快速上手。 ## 1. 安装 MySQL 首先,我们需要从 MySQL 官…...

理解智能合约:区块链在Web3中的运作机制
随着区块链技术的不断发展,“智能合约”这一概念变得越来越重要。智能合约是区块链应用的核心之一,正在推动Web3的发展,为数字世界带来了前所未有的自动化和信任机制。本文将深入探讨智能合约的基本原理、运作机制,以及它在Web3生…...

QT工程概述
在Qt中,创建 "MainWindow" 与 "Widget" 项目的主要区别在于他们的用途和功能范围: MainWindow:这是一个包含完整菜单栏、工具栏和状态栏的主窗口应用程序框架。它适合于更复 杂的应用程序,需要这些额外的用户…...

redis安装 | 远程连接
1.redis的安装 在Ubuntu下安装redis【网址】使用root账号使用apt来安装。使用apt安装比较的方便,但是安装的版本可能就不是最新的版本。 $ su root $ apt list --installed | grep redis # 查看是否安装 $ apt search redis # 查看apt中的redis版本 $ apt install…...