Redis常用内存淘汰策略?

淘汰范围来说可以分为不淘汰任何数据、只从设置了到期时间的键中淘汰和从所有键中淘汰三类。而从淘汰算法来分,又主要分为 random(随机),LRU(最近最少使用),以及 LFU(最近最不常使用)三种。

内存总是有限的,因此当 Redis 内存超出最大内存时,就需要根据一定的策略去主动的淘汰一些 key,来腾出内存,这就是内存淘汰策略。我们可以在配置文件中通过 maxmemory-policy 配置指定策略。

与到期删除策略不同,内存淘汰策略主要目的则是为了防止运行时内存超过最大内存,所以尽管最终目的都是清理内存中的一些 key,但是它们的应用场景和触发时机是不同的。

算上在 4.0 添加的两种基于 LFU 算法的策略, Redis 一共提供了八种策略供我们选择:

  • noeviction,不淘汰任何 key,直接报错。它是默认策略**。**
  • volatile-random:从所有设置了到期时间的 key 中,随机淘汰一个 Key。
  • volatile-lru: 从所有设置了到期时间的 key 中,淘汰最近最少使用的 key。
  • volatile-lfu: 从所有设置了到期时间的 key 中,淘汰最近最不常用使用的 key(4.0 新增)。
  • volatile-ttl: 从所有设置了到期时间的 key 中,优先淘汰最早过期的 key。
  • allkeys-random:从所有 key中,随机淘汰一个键(4.0 新增)。
  • allkeys-lru: 从所有 key 中,淘汰最近最少使用的 key。
  • allkeys-lfu: 从所有 key 中,淘汰最近最不常用使用的键。

淘汰范围来说可以分为不淘汰任何数据、只从设置了到期时间的键中淘汰和从所有键中淘汰三类。而从淘汰算法来分,又主要分为 random(随机),LRU(最近最少使用),以及 LFU(最近最不常使用)三种。

其中,关于 LRU 算法,它是一种非常常见的缓存淘汰算法。我们可以简单理解为 Redis 会在每次访问 key 的时候记录访问时间,当淘汰时,优先淘汰最后一次访问距离现在最早的 key。

而对于 LFU 算法,我们可以理解为 Redis 会在访问 key 时,根据两次访问时间的间隔计算并累加访问频率指标,当淘汰时,优先淘汰访问频率指标最低的 key。相比 LRU 算法,它避免了低频率的大批量查询造成的缓存污染问题

顺带一提,只要是有类似缓存机制的应用或多或少都会面对这种问题,比如老生常谈的 MySQL 连表查询,在数据量大的时候也会造成缓存污染。

LRU 的实现

LRU 的全称为 Least Recently Used,也就是最近最少使用。一般来说,LRU 会从一批 key 中淘汰上次访问时间最早的 key。

它是一种非常常见的缓存回收算法,在诸如 Guava CacheCaffeine等缓存库中都提供了类似的实现。我们自己也可以基于 JDK 的 LinkedHashMap 实现支持 LRU 算法的缓存功能。

传统的 LRU 算法实现通常会维护一个链表,当访问过某个节点后就将该节点移至链表头部。如此反复后,链表的节点就会按最近一次访问时间排序。当缓存数量到达上限后,我们直接移除尾节点,即可移除最近最少访问的缓存。

近似 LRU

Redis 中的 LRU 是近似 LRU(NearlyLRU)。当每次访问 key 时,Redis 会在结构体中记录本次访问时间,而当需要淘汰 key 时,将会从全部数据中进行抽样,然后再移除样本中上次访问时间最早的 key。

它的特点是:

  • 仅当需要时再抽样,因而不需要维护全量数据组成的链表,这避免了额外内存消耗。
  • 访问时仅在结构体上记录操作时间,而不需要操作链表节点,这避免了额外的性能消耗。

当然,有利就有弊,这种实现方式也决定 Redis 的 LRU 是并不是百分百准确的,被淘汰的 key 未必真的就是所有 key 中最后一次访问时间最早的。

#a. 抽样大小

根据上述的内容,我们不难理解,当抽样的数量越大,LRU 淘汰 key 就越准确,相对的开销也更大。因此,Redis 允许我们通过 maxmemory-samples 配置采样数量(默认为 5),从而在性能和精度上取得平衡。

#b. 缓存污染

LRU 有个最大问题,就是它只认最近一次访问时间。而如果出现系统偶尔需要一次性读取大量数据的时候,会大规模更新 key 的最近访问时间,从而导致真正需要被频繁访问的 key 因为最近一次访问时间更早而被直接淘汰。这种情况被称为缓存污染

如何选择

软件工程没有银弹,我们不可能指望存在一个能完美适用于所有场景的内存淘汰策略。

在实际场景中,我们需要结合业务特点、数据量大小、数据的冷热……等多个维度来选择合适的淘汰策略。

比如:

  • 当使用 Redis 来缓存用户动态时,由于热门用户的动态相对于普通用户往往会被更高频的访问,因此我们可以选择基于 LRU 或者 LFU 算法的策略保证热点数据不会被轻易淘汰。
  • 当使用 Redis 缓存菜单树时,由于菜单树数据大部分情况下没有明确的热点区分,因此可以考虑使用随机淘汰策略平衡各个数据的访问频率。

当然,调整淘汰策略也只是优化方案的一种。条件允许的话,在特定情况下直接增加内存、将单机改为集群或者缓存预热同样可以带来显著的收益。

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

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

相关文章

Linux--LAMP 平台部署及应用

5.1 LAMP平台概述 LAMP架构是目前成熟的企业网站应用模式之一,指的是协同工作的一整套系统和相关软件,能够提供动态Web站点服务及其应用开发环境。LAMP是一个缩写词,具体包括Linux操作系统,Apache 网站服务器、MySQL数据库服务器&…

什么是PHP中的魔术方法?

在PHP中,魔术方法(Magic Methods)是一些特殊的方法,它们具有双下划线(__)作为前缀,用于在对象的生命周期中执行一些特定的操作。这些方法不需要直接调用,而是由PHP在特定的情况下自动…

【人工智能 | 知识表示】问题规约法 谓词/符号逻辑,良好的知识表示是解题的关键!(笔记总结系列)

🤵‍♂️ 个人主页: AI_magician 📡主页地址: 作者简介:CSDN内容合伙人,全栈领域优质创作者。 👨‍💻景愿:旨在于能和更多的热爱计算机的伙伴一起成长!!&…

c#可变参数(params)关键字

通过使用 params 关键字,可以指定采用可变数量参数的方法参数。 可以发送参数声明中指定类型的参数的逗号分隔列表,也可以发送指定类型的参数数组。您也可以不发送任何参数。如果未发送任何参数,则参数列表的长度为零。 方法声明中的 param…

早上好,我的leetcode(第一期)

写在前面:每天早上到实验室早上昏昏欲睡,那不如写一题吧~ 文章目录 371. 两整数之和面试题08.05.递归乘法29.两数相除50.Pow(x,n)面试题 16.07. 最大数值2119. 反转两次的数字69. x 的平方根70.爬楼梯1631.最小体力消耗路径 371. 两整数之和 两整数之和…

基于ssm轻型卡车零部件销售平台源码和论文

随着信息化时代的到来,管理系统都趋向于智能化、系统化,轻型卡车零部件销售平台也不例外,但目前国内的市场仍都使用人工管理,市场规模越来越大,同时信息量也越来越庞大,人工管理显然已无法应对时代的变化&a…

力扣labuladong——一刷day72

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、力扣109. 有序链表转换二叉搜索树二、力扣1382. 将二叉搜索树变平衡 前言 二叉树的递归分为「遍历」和「分解问题」两种思维模式,这道题需要用到…

Caused by: java.net.ConnectException: 拒绝连接: hadoop104/192.168.124.130:4142

项目场景:hadoop102接收消息,自定义拦截器,包含hello的发往hadoop103,不包含的发往hadoop104 报错原因: 原因1: 应该先开启接收方(服务端),hadoop103,hadoop104,最后开启hadoop10…

QDialog子类的使用

背景: 我用Qt designer实现了如下效果: 但在实际使用的时候,发现OK和Cancel按钮点是点不动的。 解决方法: 需要手动添加相关信号槽函数: connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(accept()));connect…

yarn或者pnpm第一次执行的时候遇到报错yarn : 无法加载文件......因为在此系统上禁止运行脚本

报错: yarn : 无法加载文件 C:\Users\rina2\AppData\Roaming\npm\yarn.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 https:/http://go.microsoft.com/fwlink/?LinkID135170 中的 about_Execution_Policies。 解决方案&#xff1a…

前端深浅拷贝各有哪些方法,优缺点

文章目录 一、深拷贝1. JSON.parse(JSON.strigify(Str))2. lodash.deepclone3. structuredClone 二、浅拷贝总结 深浅拷贝主要是针对于引用类型而言的 一、深拷贝 1. JSON.parse(JSON.strigify(Str)) 序列化的作用是存储(对象本身存储的只是一个地址映射,如果断电&…

AWS-CDN只能备用域名访问-使用Lambda@Edge(禁止分配的域名访问)

场景:cdn使用备用域名后,希望用户只能从备用域名访问,而不是自动分配的cdn域名,这也将是一个安全漏洞,被扫描到cdn域名访问刷流量等! 【建议部署前查看】参考链接: 1.官方cdn返回示例 2.lambdae…

算法训练第三十九天|62. 不同路径、63. 不同路径 II

62. 不同路径: 题目链接 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。 问总共有…

云服务配置docker镜像容器以及常用操作命令

首先通过ssh进入云服务器。如何ssh进入云服务器。 简单讲解一下docker中镜像和容器,打个比方,镜像相当于印钱的那个模板,容器相当于从模板上拓下来的钱,不同的模板可以印出不同的钱。但容器被修改后也可以变成新的镜像&#xff0…

Postman中参数填写方式

Postman中参数填写和请求方法有关,一般接口用例请求方法GET与POST常用,所以主要是这两种请求方法请求参数填写 一、GET请求方法参数填写 1、直接在URL中填写请求参数,如直接在URL中填写: http://www.example.com:8089/userapi?unamelisi&…

c++_01_名字空间_复合类型_缺省参数_哑元函数

0 前言 C和C一样,都属于编译型语言 C和C一样,都属于强类型语言 C对C完全兼容,并提供更多面向对象的特性:语言风格更加简洁,类型检查更加严格 1 名字空间 namespace WHY?划分更精细的逻辑单元(逻辑空间)&…

Faulhaber 2.5代运动控制系统 25mNm/13W

2.5代控制系统; PWM输出; 四象限控制带; RS232或CANopen通信接口; 2250_BX4_CxD 选件,电缆和连接信息: 适配部件:

谷歌的开源供应链安全

本内容是对Go项目负责人Russ Cox 在 ACM SCORED 活动上演讲内容[1]的摘录与整理。 SCORED 是Software Supply Chain Offensive Research and Ecosystem Defenses的简称, SCORED 23[2]于2023年11月30日在丹麦哥本哈根及远程参会形式举行。 摘要 💡 谷歌在开源软件供应…

根据数据配置信息运用非集成函数处理数据

根据数据配置信息 (data configure)运用非集成函数nonensembled_map_fns处理蛋白质tensor dict。nonensembled_map_fns处理函数: correct_msa_restypes,add_distillation_flag,cast_64bit_ints,squeeze_fea…

【面经】2024年软件测试面试题大全(持续更新)附答案

📢专注于分享软件测试干货内容,欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!📢交流讨论:欢迎加入我们一起学习!📢资源分享:耗时200小时精选的「软件测试」资…