【Redis教程0x08】详解Redis过期删除策略内存淘汰策略

引言

Redis的过期删除策略和内存淘汰策略是经常被问道的问题,这两个机制都是做删除操作,但是触发的条件和使用的策略是不同的。今天就来深入理解一下这两个策略。

过期删除策略

Redis 是可以对 key 设置过期时间的,因此需要有相应的机制将已过期的键值对删除,而做这个工作的就是过期键值删除策略。

如何设置过期时间?

Redis中,设置key过期时间的命令一共有4个:

  • expire <key> <n>:设置key在n秒后过期。
  • pexpire <key> <n>:设置key在n毫秒后过期。
  • expireat <key> <n>:设置key在某个时间戳(精确到秒)之后过期。
  • pexpireat <key> <n>:设置key在某个时间戳(精确到毫秒)之后过期。

当然,在设置字符串时,也可以同时对key设置过期时间,共有3种命令:

  • set <key> <value> ex <n>:设置键值对的时候,同时指定过期时间(精确到秒);
  • set <key> <value> px <n>:设置键值对的时候,同时指定过期时间(精确到毫秒);
  • setex <key> <n> <value>:设置键值对的时候,同时指定过期时间(精确到秒);

要想查看某个key剩余的存活时间,可以使用命令TTL <key>

# 设置键值对时,指定过期时间为60s
> set name iq50 ex 60
OK# 查看过期时间
> ttl name
(integer) 56
> ttl name
(integer) 50# 可以通过PERSIST <key>命令取消过期时间
> persist name
(integer) 1# -1表示永不过期
> ttl name
(integer) -1

如何判定key已过期了?

每当我们对一个 key 设置了过期时间时,Redis 会把该 key 带上过期时间存储到一个**过期字典(expires dict)**中,也就是说「过期字典」保存了数据库中所有 key 的过期时间。
过期字典存储在 redisDb 结构中,如下:

typedef struct redisDb {dict *dict;    /* 数据库键空间,存放着所有的键值对 */dict *expires; /* 过期字典:存储键的过期时间 */....
} redisDb;

过期字典数据结构结构如下:

  • 过期字典的 key 是一个指针,指向某个键对象;
  • 过期字典的 value 是一个 long long 类型的整数,这个整数保存了 key 的过期时间;

过期字典数据结构如下图所示:
image.png
字典实际上是哈希表,哈希表的最大好处就是让我们可以用 O(1) 的时间复杂度来快速查找。当我们查询一个 key 时,Redis 首先检查该 key 是否存在于过期字典中:

  • 如果不在,则正常读取键值;
  • 如果存在,则会获取该 key 的过期时间,然后与当前系统时间进行比对,如果比系统时间大,那就没有过期,否则判定该 key 已过期。

常见的3种过期删除策略

在介绍Redis的过期删除策略之前,来看一下常见的3种过期删除策略

  • 定时删除;
  • 惰性删除;
  • 定期删除;

接下来一张表分析一下各自的优缺点:

删除策略描述优点缺点
定时删除在设置key过期时间时,同时创建一个定时事件。当时间到达时,由事件处理器自动执行key的删除操作。对内存友好。可以保证过期key会被尽快删除,去释放内存。对CPU不友好。在过期key较多的情况下,会占用相当一部分CPU时间,这会对服务器的响应时间和吞吐量造成影响。
惰性删除不主动删除过期键,每次从数据库访问key时,都检测key是否过期,过期则删除该key。对CPU友好。只有每次访问时,才检查key,所以只会使用很少的系统资源。对内存不友好。如果一个key已经过期,但是我们一直没有去访问,它占用的内存空间就一直得不到释放。
定期删除每隔一段时间随机从数据库中取出一定数量的key进行检查,并删除其中的过期key。限制删除操作的执行时长和频率,减少对CPU的影响,也能删除过期数据减少对内存的无效占用。1.内存清理方面没有定时删除好也没有惰性删除使用的系统资源少。2.难以确定删除操作执行的时长和频率。

Redis的过期删除策略

基于我们上面介绍的3种过期删除策略,Redis选择了**"惰性删除+定期删除"两种策略配合使用**,以求在合理使用CPU时间和避免内存浪费之间取得平衡。
Question1:Redis是怎么实现惰性删除的呢?
Redis的惰性删除由 db.c 文件中的 expireIfNeeded 函数实现,代码如下:

int expireIfNeeded(redisDb *db, robj *key) {// 判断 key 是否过期if (!keyIsExpired(db,key)) return 0;..../* 删除过期键 */....// 如果 server.lazyfree_lazy_expire 为 1 表示异步删除,反之同步删除;return server.lazyfree_lazy_expire ? dbAsyncDelete(db,key) :dbSyncDelete(db,key);
}

Redis 在访问或者修改 key 之前,都会调用 expireIfNeeded 函数对其进行检查,检查 key 是否过期:

  • 如果过期,则删除该 key,至于选择异步删除,还是选择同步删除,根据 lazyfree_lazy_expire 参数配置决定(Redis 4.0版本开始提供参数),然后返回 null 客户端;
  • 如果没有过期,不做任何处理,然后返回正常的键值对给客户端;

Question2:Redis是怎么实现定期删除的呢?
再回忆一下,定期删除策略的做法:每隔一段时间「随机」从数据库中取出一定数量的 key 进行检查,并删除其中的过期key。
**间隔时间多长?**在 Redis 中,默认每秒进行 10 次过期检查(相当于每100ms一次),此配置可通过 Redis 的配置文件 redis.conf 进行配置,配置键为 hz 它的默认值是 hz 10。
**随机抽查的数量多少?**随机抽查的数量由 ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP 定义的,它是写死在代码中的,数值是 20。
接下来看一下定期删除的流程:

  1. 从过期字典中随机抽取 20 个 key;
  2. 检查这 20 个 key 是否过期,并删除已过期的 key;
  3. 如果本轮检查的已过期 key 的数量,超过 5 个,也就是「已过期 key 的数量」占比「随机抽取 key 的数量」大于 25%,则继续重复步骤 1;如果已过期的 key 比例小于 25%,则停止继续删除过期 key,然后等待下一轮再检查。

由此可见,定期删除是一个循环的流程。

内存淘汰策略

之前我们介绍的是Redis的过期删除策略,是删除已过期的key,而当Redis的运行内存已经超过Redis设置的最大内存之后,则会使用内存淘汰策略删除符合条件的key,以此保证Redis的高效运行。

如何设置Redis最大运行内存?

在配置文件 redis.conf 中,可以通过参数 maxmemory <bytes> 来设定最大运行内存,只有在 Redis 的运行内存达到了我们设置的最大运行内存,才会触发内存淘汰策略。 不同位数的操作系统,maxmemory 的默认值是不同的:

  • 在 64 位操作系统中,maxmemory 的默认值是 0,表示没有内存大小限制,那么不管用户存放多少数据到 Redis 中,Redis 也不会对可用内存进行检查,直到 Redis 实例因内存不足而崩溃也无作为。
  • 在 32 位操作系统中,maxmemory 的默认值是 3G,因为 32 位的机器最大只支持 4GB 的内存,而系统本身就需要一定的内存资源来支持运行,所以 32 位操作系统限制最大 3 GB 的可用内存是非常合理的,这样可以避免因为内存不足而导致 Redis 实例崩溃

Redis内存淘汰策略有哪些?

Redis 内存淘汰策略共有八种,这八种策略大体分为「不进行数据淘汰」和「进行数据淘汰」两类策略。
1、不进行数据淘汰的策略
noeviction(Redis3.0之后,默认的内存淘汰策略) :它表示当运行内存超过最大设置内存时,不淘汰任何数据,这时如果有新的数据写入,会报错通知禁止写入,不淘汰任何数据,但是如果没用数据写入的话,只是单纯的查询或者删除操作的话,还是可以正常工作。
2、进行数据淘汰的策略
针对「进行数据淘汰」这一类策略,又可以细分为「在设置了过期时间的数据中进行淘汰」和「在所有数据范围内进行淘汰」这两类策略。
在设置了过期时间的数据中进行淘汰:

  • volatile-random:随机淘汰设置了过期时间的任意键值;
  • volatile-ttl:优先淘汰更早过期的键值。
  • volatile-lru(Redis3.0 之前,默认的内存淘汰策略):淘汰所有设置了过期时间的键值中,最久未使用的键值;
  • volatile-lfu(Redis 4.0 后新增的内存淘汰策略):淘汰所有设置了过期时间的键值中,最少使用的键值;

在所有数据范围内进行淘汰:

  • allkeys-random:随机淘汰任意键值;
  • allkeys-lru:淘汰整个键值中最久未使用的键值;
  • allkeys-lfu(Redis 4.0 后新增的内存淘汰策略):淘汰整个键值中最少使用的键值。

我们可以通过命令查看当前Redis使用的内存淘汰策略:

127.0.0.1:6379> config get maxmemory-policy
1) "maxmemory-policy"
2) "noeviction"

可以看出,当前 Redis 使用的是 noeviction 类型的内存淘汰策略,它是 Redis 3.0 之后默认使用的内存淘汰策略,表示当运行内存超过最大设置内存时,不淘汰任何数据,但新增操作会报错。
怎么修改内存淘汰策略?
有两种方式可选:

  1. 通过config set maxmemory-policy <策略>命令设置。它的优点是设置之后立即生效,不需要重启 Redis 服务,缺点是重启 Redis 之后,设置就会失效。
  2. 通过修改 Redis 配置文件修改,设置“maxmemory-policy <策略>”,它的优点是重启 Redis 服务后配置不会丢失,缺点是必须重启 Redis 服务,设置才能生效。

总结

Redis 使用的过期删除策略是「惰性删除+定期删除」,删除的对象是已过期的 key。
image.png
内存淘汰策略是解决内存过大的问题,当 Redis 的运行内存超过最大运行内存时,就会触发内存淘汰策略,Redis 4.0 之后共实现了 8 种内存淘汰策略,我也对这 8 种的策略进行分类,如下:
image.png

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

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

相关文章

Aigtek:功率放大器的定义、指标参数及性能特点

功率放大器是一种电子器件或电路&#xff0c;用于将输入信号的功率放大到更高的功率级别。它在各种应用中起到关键的作用&#xff0c;例如音频放大器、射频放大器、激光放大器等。下面西安安泰将介绍功率放大器的定义、指标参数以及其性能特点。 功率放大器的定义&#xff1a; …

自动发卡平台源码优化版配套免签个人支付宝微信插件

这款免签个人支付宝微信插件&#xff0c;配套的是 自动发卡平台源码优化版&#xff0c;支持个人免签支付 其他系统的不支持&#xff01;

政安晨:专栏目录【TensorFlow与Keras实战演绎机器学习】

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: TensorFlow与Keras实战演绎机器学习 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 本篇是作者政安晨的专栏《TensorFlow与Keras…

33.HarmonyOS App(JAVA)鸿蒙系统app数据库增删改查

33.HarmonyOS App(JAVA)鸿蒙系统app数据库增删改查 关系数据库 关系对象数据库&#xff08;ORM&#xff09; 应用偏好数据库 分布式数据库 关系型数据库&#xff08;Relational Database&#xff0c;RDB&#xff09;是一种基于关系模型来管理数据的数据库。HarmonyOS关系型…

光明源@智慧公厕的建设要求是什么

作为城市公共卫生设施的重要组成部分&#xff0c;智慧公厕的建设要求愈发受到重视。它们不仅是城市形象的窗口&#xff0c;更是为民众提供便捷、舒适的卫生服务的重要载体。那么&#xff0c;究竟什么样的要求才能确保智慧公厕的高效建设呢&#xff1f;今日&#xff0c;让我们一…

基于Java仓库管理系统设计与实现(源码+部署文档+论文)

博主介绍&#xff1a; ✌至今服务客户已经1000、专注于Java技术领域、项目定制、技术答疑、开发工具、毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精彩专栏 推荐订阅 &#x1f447;&#x1f3fb; 不然下次找不到 Java项目精品实…

【STM32CubeMX(3)】GPIO上拉输入——读取按键状态

通过本节可以学习到&#xff1a; 如何在CubeMX配置上拉输入什么是上拉输入如何读取一个GPIO的输入状态 软件环境&#xff1a; STM32CubeMX version6.10.0 Keil_v5&#xff08;MDK-ARM&#xff09; version 5.32 硬件环境&#xff1a; STM32F103C8T6最小系统板&#xff08;…

基于双vip+GTID的半同步主从复制集群项目(MySQL集群)

项目标题&#xff1a;基于keepalivedGTID的半同步主从复制MySQL集群 准备七台机器&#xff0c;其中有四台时MySQL服务器&#xff0c;搭建主从复制的集群&#xff0c;一个master&#xff0c;2个slave服务器&#xff0c;一个延迟备份服务器。同时延迟备份服务器也可以充当异地备…

软件测试基础理论、测试用例及设计方法、易混淆概念总结【软件测试】

一.软件测试基础理论 1.软件定义 软件是计算机系统中与硬件相互依存的一部分&#xff0c;包括程序、数据以及与其相关文档 的完整集合。 程序是按事先设计的功能和性能要求执行的指令序列&#xff1b; 数据是使程序能正常操作信息的数据结构&#xff1b; 文档是与程序开发、维…

MongoDB Atlas维护指南:常见类型、注意事项与窗口设置

为了给Atlas用户更好的产品体验&#xff0c;MongoDB产品团队会进行定期维护。 本文将会介绍&#xff1a; 常见维护项目种类及频率&#xff0c;注意事项维护期间的影响及建议维护窗口设置说明维护告警设置和邮件通知范例 维护窗口常见项目 定期SSL证书轮换软件升级&#xff…

金三银四面试题(一):JVM类加载与垃圾回收

面试过程中最经典的一题&#xff1a; 请你讲讲在JVM中类的加载过程以及垃圾回收&#xff1f; 加载过程 当Java虚拟机&#xff08;JVM&#xff09;启动时&#xff0c;它会通过类加载器&#xff08;ClassLoader&#xff09;加载Java类到内存中。类加载是Java程序运行的重要组成…

WhatsApp被封如何解封?附账号防封技巧

相信各位小伙伴已经发现&#xff0c;WhatsApp新一轮风控已经启动&#xff0c;不少小伙伴已经受到封号潮的冲击。无论是老号还是新号都难以幸免。为了防止WhatsApp客户数据和聊天信息的丢失&#xff0c;针对封号的防封攻略请收藏&#xff01; 一、WhatsApp被封的8个原因 1、被过…