300分钟吃透分布式缓存-23讲:Redis是如何淘汰key的?

淘汰原理
首先我们来学习 Redis 的淘汰原理。

系统线上运行中,内存总是昂贵且有限的,在数据总量远大于 Redis 可用的内存总量时,为了最大限度的提升访问性能,Redis 中只能存放最新最热的有效数据。

当 key 过期后,或者 Redis 实际占用的内存超过阀值后,Redis 就会对 key 进行淘汰,删除过期的或者不活跃的 key,回收其内存,供新的 key 使用。Redis 的内存阀值是通过 maxmemory 设置的,而超过内存阀值后的淘汰策略,是通过 maxmemory-policy 设置的,具体的淘汰策略后面会进行详细介绍。Redis 会在 2 种场景下对 key 进行淘汰,第一种是在定期执行 serverCron 时,检查淘汰 key;第二种是在执行命令时,检查淘汰 key。

第一种场景,Redis 定期执行 serverCron 时,会对 DB 进行检测,清理过期 key。清理流程如下。首先轮询每个 DB,检查其 expire dict,即带过期时间的过期 key 字典,从所有带过期时间的 key 中,随机选取 20 个样本 key,检查这些 key 是否过期,如果过期则清理删除。如果 20 个样本中,超过 5 个 key 都过期,即过期比例大于 25%,就继续从该 DB 的 expire dict 过期字典中,再随机取样 20 个 key 进行过期清理,持续循环,直到选择的 20 个样本 key 中,过期的 key 数小于等于 5,当前这个 DB 则清理完毕,然后继续轮询下一个 DB。

在执行 serverCron 时,如果在某个 DB 中,过期 dict 的填充率低于 1%,则放弃对该 DB 的取样检查,因为效率太低。如果 DB 的过期 dict 中,过期 key 太多,一直持续循环回收,会占用大量主线程时间,所以 Redis 还设置了一个过期时间。这个过期时间根据 serverCron 的执行频率来计算,5.0 版本及之前采用慢循环过期策略,默认是 25ms,如果回收超过 25ms 则停止,6.0 非稳定版本采用快循环策略,过期时间为 1ms。

第二种场景,Redis 在执行命令请求时。会检查当前内存占用是否超过 maxmemory 的数值,如果超过,则按照设置的淘汰策略,进行删除淘汰 key 操作。

淘汰方式
Redis 中 key 的淘汰方式有两种,分别是同步删除淘汰和异步删除淘汰。在 serverCron 定期清理过期 key 时,如果设置了延迟过期配置 lazyfree-lazy-expire,会检查 key 对应的 value 是否为多元素的复合类型,即是否是 list 列表、set 集合、zset 有序集合和 hash 中的一种,并且 value 的元素数大于 64,则在将 key 从 DB 中 expire dict 过期字典和主 dict 中删除后,value 存放到 BIO 任务队列,由 BIO 延迟删除线程异步回收;否则,直接从 DB 的 expire dict 和主 dict 中删除,并回收 key、value 所占用的空间。在执行命令时,如果设置了 lazyfree-lazy-eviction,在淘汰 key 时,也采用前面类似的检测方法,对于元素数大于 64 的 4 种复合类型,使用 BIO 线程异步删除,否则采用同步直接删除。

淘汰策略
在这里插入图片描述
Redis 提供了 8 种淘汰策略对 key 进行管理,而且还引入基于样本的 eviction pool,来提升剔除的准确性,确保 在保持最大性能 的前提下,剔除最不活跃的 key。eviction pool 主要对 LRU、LFU,以及过期 dict ttl 内存管理策略 生效。处理流程为,当 Redis 内存占用超过阀值后,按策略从主 dict 或者带过期时间的 expire dict 中随机选择 N 个 key,N 默认是 5,计算每个 key 的 idle 值,按 idle 值从小到大的顺序插入 evictionPool 中,然后选择 idle 最大的那个 key,进行淘汰。
在这里插入图片描述
选择淘汰策略时,可以通过配置 Redis 的 maxmemory 设置最大内存,并通 maxmemory_policy 设置超过最大内存后的处理策略。如果 maxmemory 设为 0,则表明对内存使用没有任何限制,可以持续存放数据,适合作为存储,来存放数据量较小的业务。如果数据量较大,就需要估算热数据容量,设置一个适当的值,将 Redis 作为一个缓存而非存储来使用。

Redis 提供了 8 种 maxmemory_policy 淘汰策略来应对内存超过阀值的情况。

第一种淘汰策略是 noeviction,它是 Redis 的默认策略。在内存超过阀值后,Redis 不做任何清理工作,然后对所有写操作返回错误,但对读请求正常处理。noeviction 适合数据量不大的业务场景,将关键数据存入 Redis 中,将 Redis 当作 DB 来使用。

第二种淘汰策略是 volatile-lru,它对带过期时间的 key 采用最近最少访问算法来淘汰。使用这种策略,Redis 会从 redisDb 的 expire dict 过期字典中,首先随机选择 N 个 key,计算 key 的空闲时间,然后插入 evictionPool 中,最后选择空闲时间最久的 key 进行淘汰。这种策略适合的业务场景是,需要淘汰的key带有过期时间,且有冷热区分,从而可以淘汰最久没有访问的key。

第三种策略是 volatile-lfu,它对带过期时间的 key 采用最近最不经常使用的算法来淘汰。使用这种策略时,Redis 会从 redisDb 中的 expire dict 过期字典中,首先随机选择 N 个 key,然后根据其 value 的 lru 值,计算 key 在一段时间内的使用频率相对值。对于 lfu,要选择使用频率最小的 key,为了沿用 evictionPool 的 idle 概念,Redis 在计算 lfu 的 Idle 时,采用 255 减去使用频率相对值,从而确保 Idle 最大的 key 是使用次数最小的 key,计算 N 个 key 的 Idle 值后,插入 evictionPool,最后选择 Idle 最大,即使用频率最小的 key,进行淘汰。这种策略也适合大多数 key 带过期时间且有冷热区分的业务场景。

第四种策略是 volatile-ttl,它是对带过期时间的 key 中选择最早要过期的 key 进行淘汰。使用这种策略时,Redis 也会从 redisDb 的 expire dict 过期字典中,首先随机选择 N 个 key,然后用最大无符号 long 值减去 key 的过期时间来作为 Idle 值,计算 N 个 key 的 Idle 值后,插入evictionPool,最后选择 Idle 最大,即最快就要过期的 key,进行淘汰。这种策略适合,需要淘汰的key带过期时间,且有按时间冷热区分的业务场景。

第五种策略是 volatile-random,它是对带过期时间的 key 中随机选择 key 进行淘汰。使用这种策略时,Redis 从 redisDb 的 expire dict 过期字典中,随机选择一个 key,然后进行淘汰。如果需要淘汰的key有过期时间,没有明显热点,主要被随机访问,那就适合选择这种淘汰策略。

第六种策略是 allkey-lru,它是对所有 key,而非仅仅带过期时间的 key,采用最近最久没有使用的算法来淘汰。这种策略与 volatile-lru 类似,都是从随机选择的 key 中,选择最长时间没有被访问的 key 进行淘汰。区别在于,volatile-lru 是从 redisDb 中的 expire dict 过期字典中选择 key,而 allkey-lru 是从所有的 key 中选择 key。这种策略适合,需要对所有 key 进行淘汰,且数据有冷热读写区分的业务场景。
在这里插入图片描述
第七种策略是 allkeys-lfu,它也是针对所有 key 采用最近最不经常使用的算法来淘汰。这种策略与 volatile-lfu 类似,都是在随机选择的 key 中,选择访问频率最小的 key 进行淘汰。区别在于,volatile-flu从expire dict 过期字典中选择 key,而 allkeys-lfu 是从主 dict 中选择 key。这种策略适合的场景是,需要从所有的 key 中进行淘汰,但数据有冷热区分,且越热的数据访问频率越高。

最后一种策略是 allkeys-random,它是针对所有 key 进行随机算法进行淘汰。它也是从主 dict 中随机选择 key,然后进行删除回收。如果需要从所有的 key 中进行淘汰,并且 key 的访问没有明显热点,被随机访问,即可采用这种策略。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一个足球粉丝该怎么建个个人博客?

做一个个人博客第一步该怎么做? 好多零基础的同学们不知道怎么迈出第一步。 那么,就找一个现成的模板学一学呗,毕竟我们是高贵的Ctrl c v 工程师。 但是这样也有个问题,那就是,那些模板都,太!…

oracle 获取两个时间相差天数,以及指定一个日期相差天数后的日期

1、获取两个时间相差天数 -- 两个日期相差天数 select (trunc(TO_DATE( 2024-02-28, YYYY-MM-DD ) -TO_DATE( 2024-02-25, YYYY-MM-DD ) )1) from dual2、获取日期减去指定天数后的时间 -- 两个日期相差天数的日期 select (TRUNC(TO_DATE( 2024-02-25, YYYY-MM-DD )- (trunc…

java-ssm-jsp-基于ssm的宠物领养系统的设计与实现

java-ssm-jsp-基于ssm的宠物领养系统的设计与实现 获取源码——》公主号:计算机专业毕设大全

jupyter notebook 调整深色背景与单元格宽度与自动换行

# 安装jupyter主题 pip install jupyterthemes # 列举主题 jt -l # 设置主题 jt -t chesterish设置宽度 打开users 当前用户目录下的custom.css文件 写入.container { width:80% !important; } 即可 设置自动换行 查找创建这个目录以及文件notebook.json 写入配置 “li…

PHAMB: 病毒数据分箱

Genome binning of viral entities from bulk metagenomics data | Nature Communications 安装 ### New dependencies *Recommended* conda install -c conda-forge mamba mamba create -n phamb python3.9 conda activate phamb mamba install -c conda-forge -c biocond…

Python基础!入门必备知识及基本语句,初学者必过的一道门槛!

Python入门必备知识 1 标识符 标识符是编程时使用的名字,用于给变量、函数、语句块等命名,Python中标识符由字母、数字、下划线组成,不能以数字开头,区分大小写。 ①以下划线开头的标识符有特殊含义,单下划线开头的…

【vue.js】文档解读【day 4】 | 事件处理

如果阅读有疑问的话,欢迎评论或私信!! 文章目录 事件处理前言监听事件内联事件处理器方法事件处理器方法与内联事件判断在内联处理器中调用方法在内联事件处理器中访问事件参数修饰符事件修饰符按键修饰符常规按键别名系统按键别名组合按键ex…

java-ssm-jsp-基于ssm的宝文理学生社团管理系统

java-ssm-jsp-基于ssm的宝文理学生社团管理系统 获取源码——》公主号:计算机专业毕设大全

【数据分享】2013-2022年全国范围逐月CO栅格数据(免费获取)

空气质量数据是在我们日常研究中经常使用的数据!之前我们给大家分享了2000-2022年全国范围逐月的PM2.5栅格数据和2013-2022年全国范围逐月SO2栅格数据(可查看之前的文章获悉详情)。 本次我们给大家带来的是2013-2022年全国范围的逐月的CO栅格…

STL容器之哈希的补充——其他哈希问题

1.其他哈希问题 ​ 减少了空间的消耗; 1.1位图 ​ 位图判断在不在的时间复杂度是O(1),速度特别快; ​ 使用哈希函数直接定址法,1对1映射; ​ 对于海量的数据判断在不在的问题,使用之前的一些结构已经无法满足&…

鸿蒙开发-UI-动画-页面内动画

鸿蒙开发-UI-组件2 鸿蒙开发-UI-组件3 鸿蒙开发-UI-气泡/菜单 鸿蒙开发-UI-页面路由 鸿蒙开发-UI-组件导航-Navigation 鸿蒙开发-UI-组件导航-Tabs 鸿蒙开发-UI-图形-图片 鸿蒙开发-UI-图形-绘制几何图形 鸿蒙开发-UI-图形-绘制自定义图形 文章目录 前言 一、概述 二、页面内…

基于springboot+vue的美食烹饪互动平台

博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战,欢迎高校老师\讲师\同行交流合作 ​主要内容:毕业设计(Javaweb项目|小程序|Pyt…

Ainx的消息封装

📕作者简介: 过去日记,致力于Java、GoLang,Rust等多种编程语言,热爱技术,喜欢游戏的博主。 📗本文收录于Ainx系列,大家有兴趣的可以看一看 📘相关专栏Rust初阶教程、go语言基础系列…

【深度学习笔记】6_9 深度循环神经网络deep-rnn

注:本文为《动手学深度学习》开源内容,部分标注了个人理解,仅为个人学习记录,无抄袭搬运意图 6.9 深度循环神经网络 本章到目前为止介绍的循环神经网络只有一个单向的隐藏层,在深度学习应用里,我们通常会用…

宿主机连接不上vmware中的虚拟机排查思路

1、简介 在前文中,我们遇到了电脑连接网络后无法浏览网页的情况,其中有一种方式就是将网络适配器卸载,然后重启机器。今天在使用vmware中的虚拟机时,发现和宿主机网段不一致,导致宿主机访问不了虚拟机,主要…

Vue快速开发一个主页

前言 这里讲述我们如何快速利用Vue脚手架快速搭建一个主页。 页面布局 el-container / el-header / el-aside / el-main&#xff1a;https://element.eleme.cn/#/zh-CN/component/container <el-container><el-header style"background-color: #4c535a"…

【算法沉淀】最长回文子串

&#x1f389;&#x1f389;欢迎光临&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;特别推荐给大家我的最新专栏《数据结构与算法&#xff1a;初学者入门指南》&#x1f4d8;&am…

探索代理服务器:保护您的网络安全与隐私

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Linux ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 隐藏真实IP地址&#xff1a; 访问控制&#xff1a; 加速访问速度&#xff1a; 过滤内容&#xff1a; 突破访问限制&#xff1…

【Linux系统】线程

目录 一.线程的概念 (1)地址空间是进程的资源窗口 (2)轻量级进程 二.线程的理解 1.Linux中线程的实现方案 2. 线程VS进程 3.线程比进程更加轻量化 4.线程的优点 5.线程的缺点 6.线程共享的资源 7.线程私有的资源 三.地址空间虚拟到物理的转化 1.页框 2.重新理解文…

Vessel - Linux hackthebox

#hard #runc #RE #Nodejs-SQLI Enumeration .git leak 使用 dumpall 下载 .git 打开 routes/index.js 可以看到网站使用 nodejs mysql 编写&#xff0c;且只有登录功能 router.post(/api/login, function(req, res) {let username req.body.username;let password req…