Redis内存淘汰策略有哪些

news/2024/12/20 0:54:32/

Redis内存淘汰策略有哪些

简单来说:
  1. volatile-lru(least recently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

  2. volatile-ttl:-------------------要过期的数据淘汰

  3. volatile-random:------------任意选择数据淘汰

  4. allways-lru:从数据集(server.db[i].dict)中移除最近最少使用的数据淘汰

  5. allways-random:-----------------任意选择数据淘汰

  6. no-eviction(默认内存淘汰策略):禁止驱逐数据,内存不足以写入新数据时,新写入的操作会报错。

4.0 版本后增加以下两种:

  1. volatile-lfu(least frequently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最不经常使用的数据淘汰

  2. allkeys-lfu(least frequently used):从数据集(server.db[i].dict)中移除最不经常使用的数据淘汰。

allkeys-xxx 表示从所有的键值中淘汰数据,而 volatile-xxx 表示从设置了过期时间的键值中淘汰数据。

volatile前缀的策略从expire字典中查找

allkeys前缀的策略从dict字典中查找

内存淘汰算法和原理

Redis的内存淘汰策略是指,当内存的使用率达到maxmemory的上限的时候,他的一种内存释放的行为。有以下四种:

  • 默认策略,不进行任何淘汰,内存不足容纳更多数据时,对写操作返回错误

  • Random随机策略,随机删除某个key

  • TTL算法,就是在过期的key中找到更早过期的key进行有限移除。

  • LRU算法,移除最近很少使用的key

  • LFU算法,跟LRU算法类似,增加了频率的维度来判定热点key

LRU算法是一种比较常见的内存淘汰机制,在Redis里面会维护一个大小16的候选池,候选词里面的数据会根据时间进行排序。然后每一次随机抽取5个key放入这个候选池中,当候选池满了后,访问时间间隔最大的key会被淘汰掉,实现最少使用的key从内存中淘汰掉。但是也会存在一个问题,假如一个key很长时间没有访问,但最近一次偶然访问,LRU会认为该key是热点key

基于该问题,在Redis4引入LFU算法,增加访问频率的维度来统计数据的热点情况。采用两个双向链表的方式形成二维结构,一个用来记录访问的频次,一个用来记录访问频次相同的元素。添加元素时默认频次为1,找到相同频次的节点添加对应头部,当元素被访问的时候,就会增加他的访问频率,并移动到下一个节点。如果单纯的根据频次来淘汰数据,就会出现前期经常访问,后期不经常,就很难被淘汰。基于该问题LFU算法根据访问频次和上次访问时间间隔进行淘汰。如果一个数据有读和写就增加他的频率,没有则减少。就能真正实现对非热点key的淘汰。当然LFU算法也有缺点,相对于LRU,它多维护了访问频率的维度,同时实现上也比LRU复杂。

详细来说
  1. volatile - lru(least recently used)

    • 原理:

      • LRU 是一种常见的缓存置换算法。在 Redis 中,当采用volatile - lru策略时,主要关注的是已经设置了过期时间的键空间(server.db[i].expires)。Redis 会通过某种方式记录每个键的最后访问时间。当需要淘汰键来释放内存时,它会在这个设置了过期时间的键集合中,选择那些最近最少被使用的键进行淘汰。例如,假设有一组带有过期时间的键key1key2key3等,Redis 会记录它们的最后访问时间,当内存不足需要淘汰时,会找出最后访问时间最早的那个键进行淘汰。

    • 应用场景:

      • 这种策略适用于大部分缓存场景,特别是对数据时效性有要求,且希望优先保留最近使用过的数据的情况。比如,在一个网页缓存系统中,用户频繁访问的网页应该被保留,而那些长时间未被访问且带有过期时间的网页缓存数据可以被淘汰,以腾出空间给新的缓存数据。

    • 实现细节:

      • Redis 实际上使用了一种近似 LRU 算法,因为严格的 LRU 算法需要记录每个键的精确访问时间序列,这会消耗大量的内存。Redis 通过维护一个简单的链表结构来近似实现 LRU。每次访问一个键时,这个键会被移动到链表的头部,而链表尾部的键就代表最近最少使用的键。当需要淘汰时,从链表尾部选择键进行淘汰。不过,这种近似算法可能会导致一些并不是真正最近最少使用的键被淘汰,但在大多数情况下能够有效地平衡内存和性能。

  2. volatile - ttl

    • 原理:

      • 该策略主要针对设置了过期时间的数据集(server.db[i].expires)。它会优先淘汰那些距离过期时间最近的键。Redis 内部会维护每个键的过期时间信息,在需要淘汰键时,比较所有设置了过期时间的键的剩余生存时间(Time - To - Live,TTL),选择 TTL 值最小的键进行淘汰。例如,有键keyA还有 10 秒过期,键keyB还有 60 秒过期,当采用volatile - ttl策略且需要淘汰键时,会优先淘汰keyA

    • 应用场景:

      • 适用于对数据时效性要求极高的场景。例如,在一个限时促销活动的缓存系统中,对于限时优惠信息的缓存键,可以采用这种策略。这样可以确保那些即将过期的促销信息缓存首先被淘汰,避免占用过多内存,同时也符合业务逻辑,即优先清除即将失效的数据。

    • 实现细节:

      • Redis 在内部数据结构中存储了每个键的过期时间,通过遍历server.db[i].expires中的键,计算每个键的 TTL,并找到最小 TTL 的键进行淘汰。这个过程需要一定的时间来遍历和比较,但由于通常是在内存中操作,并且只有在内存紧张需要淘汰键时才会执行,所以在合理的数据集规模下,对性能的影响是可以接受的。

  3. volatile - random

    • 原理:

      • 同样是针对设置了过期时间的数据集(server.db[i].expires),当采用volatile - random策略时,Redis 会在这个数据集中随机选择一个键进行淘汰。每次淘汰操作就像从一个装有设置了过期时间键的 “抽奖箱” 中随机抽取一个键来淘汰,没有考虑键的使用频率、过期时间等因素。

    • 应用场景:

      • 这种策略适用于对淘汰顺序没有特别要求,只要是从带有过期时间的键中淘汰一个即可的场景。例如,在一个简单的测试环境或者对数据一致性要求不高的缓存场景中,可以使用这种策略。它的实现相对简单,不需要复杂的记录和比较操作。

    • 实现细节:

      • 在代码实现上,Redis 可能会通过随机数生成器从server.db[i].expires集合中选择一个索引位置,然后淘汰该位置对应的键。这种随机选择的方式简单直接,但可能会导致一些 “运气不好” 的情况,比如连续淘汰了比较重要或者还很有用的带有过期时间的键。

  4. allkays - lru

    • 原理:

      • 此策略关注的是整个数据集(server.db[i].dict),而不仅仅是设置了过期时间的键。它会在整个键空间中挑选最近最少使用的键进行淘汰。与volatile - lru类似,Redis 会记录键的最后访问时间(通过近似 LRU 算法),当内存不足需要淘汰键时,从所有键中找到最近最少使用的键进行淘汰。例如,在一个包含大量持久化键和临时键的 Redis 实例中,会考虑所有键的使用情况来决定淘汰对象。

    • 应用场景:

      • 适用于不区分数据是否有过期时间,只希望保留最近使用过的数据的场景。比如,在一个通用的缓存服务器中,存储了各种类型的数据,包括一些没有设置过期时间的配置信息和有过期时间的临时数据,当内存紧张时,使用allkeys - lru可以根据数据的使用频率来合理地淘汰键,优化内存利用。

    • 实现细节:

      • 同样采用近似 LRU 算法,通过维护一个链表结构来记录键的访问情况。每次访问键时将其移动到链表头部,淘汰键时从链表尾部选择。这种方式能够在整个数据集范围内有效地管理内存,使得内存中保留的大部分是经常使用的数据。

  5. allkays - random

    • 原理:

      • 针对整个数据集(server.db[i].dict),采用随机选择的方式淘汰键。无论键是否设置了过期时间,当需要淘汰键来释放内存时,Redis 会在所有键中随机抽取一个进行淘汰。这是一种非常简单直接的内存淘汰策略。

    • 应用场景:

      • 适用于对内存淘汰顺序没有严格要求,并且希望以一种简单的方式来管理内存的场景。例如,在一个对数据重要性和使用频率没有明确区分的小型 Redis 实例中,或者在一些简单的测试和开发环境中,可以使用这种策略。

    • 实现细节:

      • 实现方式类似于volatile - random,通过随机数生成器从整个数据集(server.db[i].dict)中选择一个键进行淘汰。这种策略的优点是实现简单,缺点是可能会淘汰一些比较重要或者经常使用的键,因为没有考虑键的任何属性,完全是随机操作。

  6. no - eviction(默认内存淘汰策略)

    • 原理:

      • 这是一种比较保守的策略。当内存不足以写入新数据时,Redis 不会自动淘汰任何现有的键,而是直接返回一个错误给尝试写入新数据的客户端操作。这意味着 Redis 会严格遵守数据的完整性,除非手动删除一些键或者扩大内存,否则不会因为内存不足而丢失数据。

    • 应用场景:

      • 适用于对数据完整性要求极高,不允许因为内存管理策略而丢失任何数据的场景。例如,在一些对数据准确性和持久性要求很高的金融系统或者数据存储系统中,采用no - eviction策略可以确保数据的绝对安全,即使出现内存紧张的情况,也会通过其他方式(如增加内存、手动清理数据等)来解决,而不是让 Redis 自动淘汰数据。

    • 实现细节:

      • 在代码实现上,当 Redis 检测到内存不足且采用no - eviction策略时,会在写入新数据的操作(如SET操作)中加入检查逻辑。如果内存已满,直接返回一个表示内存不足无法写入的错误码给客户端,阻止新数据的写入,而不会去触动任何淘汰键的机制。

  7. volatile - lfu(least frequently used)

    • 原理:

      • 从已设置过期时间的数据集(server.db[i].expires)中挑选最不经常使用的数据淘汰。LFU 是另一种缓存置换算法,与 LRU 关注最后访问时间不同,LFU 重点关注键的使用频率。Redis 会记录每个键的访问次数,在需要淘汰键时,从设置了过期时间的键中选择访问次数最少的键进行淘汰。例如,有键key1被访问了 3 次,键key2被访问了 1 次,当采用volatile - lfu策略且需要淘汰键时,会优先淘汰key2

    • 应用场景:

      • 适用于数据访问频率差异较大,且希望优先保留经常被访问的数据的场景。比如,在一个内容分发网络(CDN)的缓存系统中,对于热门内容的缓存键访问频率很高,而一些冷门内容的缓存键访问频率很低。采用volatile - lfu可以确保冷门的、带有过期时间的缓存数据被优先淘汰,从而更好地利用内存来缓存热门内容。

    • 实现细节:

      • Redis 为了实现 LFU,会在内部为每个键维护一个计数器来记录访问次数。这个计数器会根据一定的规则进行更新,例如每次访问键时,计数器会增加。同时,为了避免计数器无限增长,还会有一些衰减机制,使得长时间未被访问的键的访问次数逐渐降低。在淘汰键时,通过比较这些计数器的值来选择最不经常使用的键。

  8. allkeys - lfu(least frequently used)

    • 原理:

      • 从数据集(server.db[i].dict)中移除最不经常使用的数据淘汰。与volatile - lfu类似,也是基于 LFU 算法,但这个策略是在整个数据集范围内进行操作,而不仅仅是针对设置了过期时间的键。Redis 会记录所有键的访问频率,在内存紧张需要淘汰键时,从所有键中选择访问次数最少的键进行淘汰。

    • 应用场景:

      • 适用于不区分键是否有过期时间,只关注数据访问频率来管理内存的场景。例如,在一个大型的通用缓存系统中,存储了各种各样的数据,包括持久化的数据和临时的数据。通过采用allkeys - lfu策略,可以根据数据的实际使用频率来合理地淘汰键,使得内存中保留的大部分是经常被访问的数据,提高缓存的有效性。

    • 实现细节:

      • 同样会为每个键维护一个访问次数计数器,并且有相应的更新和衰减机制。在整个数据集范围内进行淘汰操作时,通过比较所有键的访问次数计数器的值来确定最不经常使用的键进行淘汰。这种策略能够有效地利用内存,根据数据的实际使用情况来优化内存空间的分配。


http://www.ppmy.cn/news/1556518.html

相关文章

Web安全攻防入门教程——hvv行动详解

Web安全攻防入门教程 Web安全攻防是指在Web应用程序的开发、部署和运行过程中,保护Web应用免受攻击和恶意行为的技术与策略。这个领域不仅涉及防御措施的实现,还包括通过渗透测试、漏洞挖掘和模拟攻击来识别潜在的安全问题。 本教程将带你入门Web安全攻…

ubuntu server 安装

1 获取ubuntu https://ubuntu.com/download/server 2 安装ubuntu 详细教程查看视频: ubunut server 安装_哔哩哔哩_bilibili

如何搭建政务服务网站?政务服务网站包含哪些内容?

政务网致力于向公众提供政府工作的相关信息、政策法规的公开和解读,促进政府与公众之间的沟通与互动。公众可以随时随地通过网站了解到当地政府工作的政策方向、政策公告、行政许可和公共服务等相关信息。 一、在政府网站的建设中,有几个关键方面需要重点关注&#…

Sql注入(靶场)14-20关

第十四关 跟上面一样闭合换成" 第一步查询库名 " and updatexml(1,concat(1,(select database())),1)# 第二步查询表名 " and updatexml(1,concat(1,(select group_concat(table_name) from information_schema.tables where table_schemasecurity)),1)# 第…

LLM模型的generate和chat函数区别

在 Hugging Face 的 transformers 库中,GPT(Generative Pre-trained Transformer)类的模型有两个常用的生成文本的方法:generate 和 chat。这两个方法在使用上有一些区别。通常公司发布的 LLM 模型会有一个基础版本,还…

实名应用分发平台的详细分析

实名的应用分发平台是指那些要求开发者或应用程序提供者进行真实身份信息认证的应用程序分发平台。这种认证机制通常是为了确保平台上的应用程序来源可靠、内容合法,并保护用户的权益和安全。以下是对实名应用分发平台的详细分析: 一、背景与目的 背景…

【ORACLE】一个允许关键字作为别名所引起的语法歧义场景

前言 最近在看SQL语法解析器,发现了antlr4提供的PlSql语法树存在一个BUG,然后我顺着这个BUG,构造了一条SQL,在ORACLE执行,如下 然后神奇的事情出现了,这个查询竟然没有返回行!t1表左关联t2&…

Windows如何安装go环境,离线安装beego

一、安装go 1、下载go All releases - The Go Programming Language 通过网盘分享的文件:分享的文件 链接: https://pan.baidu.com/s/1MCbo3k3otSoVdmIR4mpPiQ 提取码: hxgf 下载amd64.zip文件,然后解压到指定的路径 2、配置环境变量 需要新建两个环境…