Redis过期策略以及内存淘汰机制

article/2025/9/14 9:31:32

redis所以的操作都是基于内存的,而每台机器的内存大小都有限制,且全没有磁盘空间那么大,所以如何高效的使用内存对于redis来说是非常关键的。

一、Redis过期策略

如果我们一直往redis中存储数据的话,总会有占满内存的那一刻,为了不数据占满内存,这时候我们就会想的将一些不需要永久保持的数据设置一个过期时间。接下来我们看下以下几个问题:

  1. 如何设置key的过期时间?
    redis提供了四种命令来设置key的过期时间:
    (1) EXPIRE key seconds // 设置多少秒后过期
    (2) EXPIREAT key timestamp 设置 key 过期时间的时间戳(unix timestamp) 以秒计
    (3) PEXPIRE key milliseconds // 设置多少毫秒后过期
    (4) PEXPIREAT key milliseconds-timestamp // 设置 key 过期时间的时间戳(unix timestamp) 以毫秒计
    移除redis的过期时间:
    PERSIST key // 移除key的过期时间,key将保持永久
    查询剩余生存时间:
    TTL key // 以秒为单位,返回给定 key 的剩余生存时间
    PTTL key // 以毫秒为单位返回 key 的剩余的过期时间

  2. 设置完一个key的过期时间后,到了这个过期时间,这个key保存的数据还占据着内存吗?
    当key过期后,该key保存的数据还是会占据内存的,因为每当我们设置一个键的过期时间时,Redis会将该键带上过期时间存放到一个过期字典中。当key过期后,如果没有触发redis的删除策略的话,过期后的数据依然会保存在内存中的,这时候即便这个key已经过期,我们还是能够获取到这个key的数据。

  3. redis什么时候去删除过期的数据?
    redis过期删除策略通常有三种:定时删除,定期删除,惰性删除。redis使用的是:“定期删除+惰性删除”。
    (1) 定时删除
    在设置某个key 的过期时间同时,我们创建一个定时器,让定时器在该过期时间到来时,立即执行对其进行删除的操作。
    优点:定时删除对内存是最友好的,能够保存内存的key一旦过期就能立即从内存中删除。
    缺点:对CPU最不友好,在过期键比较多的时候,删除过期键会占用一部分 CPU 时间,对服务器的响应时间和吞吐量造成影响。
    (2) 定期删除
    每隔一段时间,我们就对一些key进行检查,删除里面过期的key。Redis默认每隔100ms就随机抽取部分设置了过期时间的key,检测这些key是否过期,如果过期了就将其删除。这里有两点需要注意下:

    • 默认的每隔100ms是在Redis的配置文件redis.conf中有一个属性"hz",默认为10,表示1s执行10次定期删除,即每隔100ms执行一次,可以修改这个配置的值来设置默认的间隔时间。
      在这里插入图片描述
    • 随机抽取部分,而不是全部key。因为如果Redis里面有大量key都设置了过期时间,全部都去检测一遍的话CPU负载就会很高,会浪费大量的时间在检测上面,甚至直接导致redis挂掉。所有只会抽取一部分而不会全部检查。

    优点:可以通过限制删除操作执行的时长和频率来减少删除操作对 CPU 的影响。另外定期删除,也能有效释放过期键占用的内存。
    缺点:难以确定删除操作执行的时长和频率。如果执行的太频繁,定期删除策略变得和定时删除策略一样,对CPU不友好。如果执行的太少,那又和惰性删除一样了,过期键长时间占用的内存没有及时释放的话,当我们再次获取这个过期的key时,依然会返回这个key的值,就相当于这个过期时间是无效的了。
    (3) 惰性删除
    设置该key 过期时间后,我们不去管它,当需要该key时,我们在检查其是否过期,如果过期,我们就删掉它,反之返回该key。
    优点:对 CPU友好,我们只会在使用该键时才会进行过期检查,对于很多用不到的key不用浪费时间进行过期检查。
    缺点:对内存不友好,如果一个键已经过期,但是一直没有使用,那么该键就会一直存在内存中,如果数据库中有很多这种使用不到的过期键,这些键便永远不会被删除,内存永远不会释放,从而造成内存泄漏。所以redis还引入了另一种内存淘汰机制。

二、内存淘汰机制

Redis的内存淘汰机制是指在Redis的用于缓存的内存不足时,怎么处理需要新写入且需要申请额外空间的数据。

  1. 如何设置redis内存大小?
    在配置文件redis.conf 中,可以通过参数 maxmemory 来设定最大内存。不设定该参数默认是无限制的,但是通常会设定其为物理内存的四分之三。
    在这里插入图片描述

  2. 内存淘汰方式有哪些?

    1. noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。(默认选项,一般不会选用)
    2. allkeys-lru:当内存不足以容纳新写入数据时,在整个键空间中,移除最近最少使用的key。(这个是最常用的)
    3. allkeys-lfu:当内存不足以容纳新写入数据时,在整个键空间中,移除最不经常(最少)使用的key。
    4. allkeys-random:当内存不足以容纳新写入数据时,在整个键空间中,随机移除某个key。
    5. volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。
    6. volatile-lfu:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最不经常(最少)使用的key。
    7. volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。
    8. volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。
  3. 如何设置内存淘汰方式?
    在配置文件redis.conf 中,可以通过参数maxmemory-policy来设置淘汰的方式。
    在这里插入图片描述

三、常用的淘汰算法
  1. FIFO 算法(Fist in first out:先进先出)
    FIFO 算法是一种比较容易实现的算法。它的思想:是基于队列的先进先出原则,最先进入的数据会被最先淘汰掉。这是最简单、最公平的一种思想。
    (1)实现:维护一个FIFO队列,按照时间顺序将各数据(已分配页面)链接起来组成队列,并将置换指针指向队列的队首。再进行置换时,只需把置换指针所指的数据(页面)顺次换出,并把新加入的数据插到队尾即可。
    (2)缺点:这种算法有个很严重的缺点,就是会导致缺页率增加。缺页率指的是判断一个页面置换算法优劣的指标。随着分配页面的增加,被置换的内存页面往往是被频繁访问的,因此FIFO算法会使一些页面频繁地被替换和重新申请内存,从而导致缺页率增加。由于缺页率会随着分配页面的增加而增加,使得redis的开销也逐渐增加,所以这种算法已经不再使用。
  2. LRU算法(Least recently used:最近最少使用)
    LRU算法是一种常见的缓存算法,它的思想是:最近最少使用的会被优先淘汰。如果一个数据在最近一段时间没有被访问到,那么可以认为在将来它被访问的可能性也很小。因此,当空间满时,最久没有访问的数据最先被淘汰掉。
    (1)实现:最简单的实现方法是用数组+时间戳的方式,不过这样做效率较低。因此,我们可以用双向链表(LinkedList)+ 哈希表(HashMap)实现(链表用来表示位置,哈希表用来存储和查找),在Java里有对应的数据结构LinkedHashMap。
    在这里插入图片描述
    (2)缺点:它在需要淘汰时,只是随机选取有限的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算法的相似度。
  3. LFU算法(Least frequently used:最不常使用)
    LFU算法的思想是:如果一个数据在最近一段时间很少被访问到,那么可以认为在将来它被访问的可能性也很小。因此,当空间满时,最小频率访问的数据最先被淘汰。
    实现:如果只为每个key维护了一个计数器,每次key被访问的时候,计数器增大,计数器越大,则认为访问越频繁。这样还是远远不够的,还会存在两个问题:
    (1)因为可能存在在开始一个小时内,某个key1有100万的访问量,但是在之后的一个小时内,这个key1的访问量为0了,而在这第二个小时内另外有个key2的访问量达到了20万,虽然这20万不如前面那个key1开始那个小时的100万访问量大,但是在第二个小时内这key2的访问量远大于key1的访问量,所以在第二个小时内key1依然会优先于key2被淘汰掉。
    (2)当新加入的key,由于没有被访问过,所以初始的计数器为0,如果这时候触发淘汰机制的话,就会把最先添加到key最先淘汰掉。
    所以在LFU算法中维护了这个24bit的字段,不过被分成了16 bits与8 bits两部分。第一部分:高16 bits用来记录计数器的上次缩减时间,时间戳,单位精确到分钟。第二部分:低8 bits用来记录计数器的当前数值,这个数值反映了访问频率,而不是次数。
    在redis.conf配置文件中还有2个属性可以调整LFU算法的执行参数:lfu-log-factor、lfu-decay-time。其中lfu-log-factor用来调整计数器counter的增长速度,lfu-log-factor越大,counter增长的越慢。lfu-decay-time是一个以分钟为单位的数值,用来调整counter的缩减速度。
四、总结

Redis的内存淘汰策略的选取并不会影响过期的key的处理。内存淘汰策略用于处理内存不足时的需要申请额外空间的数据;过期策略用于处理过期的缓存数据。


http://chatgpt.dhexx.cn/article/VQE63JB9.shtml

相关文章

redis过期策略和内存淘汰机制

Redis的过期策略 1 定时过期 每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除。该策略可以立即清除过期的数据,对内存很友好;但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。 2…

Redis 过期策略+conf 记录

一:redis的过期策略 三种过期键删除策略 1)定时删除:创建一个定时器,到时间立即执行删除操作(对内存友好,因为能保证过期了立马删除,但是对cpu不友好) 2)惰性删除&…

Redis之过期策略

一、设置过期时间 Redis对存储值的过期处理实际上是针对该值的键(key)处理的,即时间的设置也是设置key的有效时间。Expires字典保存了所有键的过期时间,Expires也被称为过期字段。 expire key time(以秒为单位)--这是最常用的方式…

redis的过期策略【转】

转:Redis的过期策略以及内存淘汰机制_Felix-CSDN博客_redis过期策略和内存淘汰机制 我们知道,redis中缓存的数据是有过期时间的,当缓存数据失效时,redis会删除过期数据以节省内存,那redis是怎样删除过期数据的&#xf…

主成分分析;主成分回归分析——Hald水泥问题;主成分分析案例——各地区普通高等教育发展水平综合评价;matlab

目的 对原变量加以“改造”,在不致损失原变量太多信息的条件下尽可能地降低变量地维数,即用较少的“新变量”代替原来地各变量。通过变换:用低维(主成分)近似高维(较全面)信息。 思想 若有二维…

hadoopHA

一、HA介绍 HA(High Available), 高可用,是保证业务连续性的有效解决方案,一般有两个或两个以上的节点,分为活动节点(Active)及备用节点(Standby)。 hadoop2.x之后Clouera提出了QJM/Qurom Jou…

AIDL 和 HIDL

AIDL概述 aidl是常用的android IPC方式,本文将根据一个demo来解析下AIDL的原理。 为了便于读者理解,本文不会探究Binder的实现细节,可以认为Binder在此文的分析中被看做是一个“黑盒”。 有一定经验的读者可以直接到文末看总结,最…

Linux守护进程HALD

hal(hardware abstract lever)硬件抽象。 但是Linux的hal运行于用户空间作为一个daemon进程。监听一个socket接口。等待udev发来的通知。 udev为设备加载驱动,设备可用后,往往有udev的规则,让udev通知hald表示设备变动…

.har文件使用

背景 在做web开发的过程中, 查看http请求/响应是非常常见的操作. 有时可能有这样的需求: 将某次操作的请求/响应保存下来, 给别人看或者分析, 那你可能需要har文件. 另外你还需要Fiddler来查看har文件内容 操作截图 在"Network"面板中, 将某次操作的请求保存为har…

head 命令

转载:每天一个linux命令(14):head 命令_weixin_33794672的博客-CSDN博客head 与 tail 就像它的名字一样的浅显易懂,它是用来显示开头或结尾某个数量的文字区块,head 用来显示档案的开头至标准输出中&#x…

颜色查找表LUT

查找表(LUT,LookUp Table)是图像颜色转换的强大工具,在许多图形和视频编辑器中使用。 2D LUT CLUT-from-images 2D LUT生成 def generate_identify_color_matrix(width, height, channel):img np.zeros((width, height, chan…

Hadoop HA介绍

1、HA 概述 所谓HA(High Available),即高可用(7*24小时不中断服务)。实现高可用最关键的策略是消除单点故障。Hadoop-HA严格来说应该分成各个组件的HA机制: HDFS的HA和YARN的HA。Hadoop2.0之前&#xff0c…

HAL 库

HAL库 1、初识HAL库 1.1 CMSIS 简介 CMSIS(微控制器软件接口标准):Crotex Microcontroller Software Interface Standard,是由ARM和与其合作的芯片厂商、软件工具厂商,共同制定的标准 ARM官方提供的CMSIS规范架构 …

HIDL(HAL interface definition langguage)

HIDL的相关介绍 HIDL的全称是HAL interface definition language(硬件抽象层接口定义语言),在此之前 Android 有AIDL,架构在Android binder 之上,用来定义Android 基于Binder通信的Client 与Service之间的接口。HIDL…

内部类

一、非静态内部类。 1、修饰符 非静态内部类有四个作用域,所以有四个修饰符。 private : 只能在外部类的内部使用。 protected : 可被与外部类处于同一个包中的其他类和外部类的子类所访问。 省略 : 只能被与外部类处于同一个包中的其他类访问。 public : 可…

python的类作用_python中类的作用是什么

简单来说,类是一种高级抽象,就是一种高级的数据类型,是对象的蓝图,就是用来定义你要用的对象的属性和行为的。 以下是面向对象简介 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性…

C# 内部类的作用

作用一:限制对类的可访问性 有时候会遇到这样的需求,希望一个类仅能被另一个类(以及其派生类)访问。 代码 class BaseClass {public class PublicNestedClass { }protected class ProtectedNestedClass { }private class Priva…

内部类详解

1.成员内部类 1.样例 class OutClass {class InnerClass {public String SayHi() {return "你好";}} }2.特点 内部类能够无条件的访问外部类的成员变量,外部类要访问内部类成员变量需要使用new。内部类和外部类有相同名称的变量或者是方法,…

Java 静态内部类作用

需要了解2个概念:内部类和静态修饰符static 1)首先,用内部类是因为内部类与所在外部类有一定的关系,往往只有该外部类调用此内部类。所以没有必要专门用一个Java文件存放这个类。 2)静态都是用来修饰类的内部成员的。…

java内部类的四大作用

一、内部类的作用 我们为什么需要内部类?或者说内部类为啥要存在?其主要原因有如下几点: 内部类方法可以访问该类定义所在作用域中的数据,包括被 private 修饰的私有数据内部类可以对同一包中的其他类隐藏起来内部类可以解决java …