开发者

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

开发者 https://www.devze.com 2025-04-24 08:59 出处:网络 作者: echola_mendes
目录​​​一、过期策略1、惰性删除2、定时删除3、定期删除二、内存淘汰机制​​​1、内存淘汰策略​​​2、内存淘汰算法三、Lazy-Free机制Lazy Free 与缓存淘汰的关系四、相关问题1:Redis 给缓存数据设置过期时间?
目录
  • ​​​一、过期策略
    • 1、惰性删除
    • 2、定时删除
    • 3、定期删除
  • 二、内存淘汰机制
    • ​​​1、内存淘汰策略
    • ​​​2、内存淘汰算法
  • 三、Lazy-Free机制
    • Lazy Free 与缓存淘汰的关系
  • 四、相关问题
    • 1:Redis 给缓存数据设置过期时间?
    • 2:Redis 是如何判断数据是否过期的呢?
    • 3:大量 key 集中过期怎么办?
  • 总结

    在谈Redis过期概念时,先抛出几个问题:

    • 1:Redis 给缓存数据设置过期时间?
    • 2:Redis 是如何判断数据是否过期的呢?
    • 3:大量 key 集中过期怎么办?

    那么代入问题,根据概念思考这几个问题吧

    Redis有三种数据过期策略:定时删除,惰性删除,定期删除

    ​​​一、过期策略

    1、惰性删除

    当读/写一个已经过期的key时,会触发惰性删除策略,判断key是否过期,如果过期了直接删除掉这个key

    简而言之:就是当被读写的时候,再判断是否过期再删除

    对于过期的key不作任何处理,当获取key时检查key是否过期,过期就删除,否则直接返回。

    • 优点:删除key操作只在取出key时发生,只删除当前key,占用CPU少。
    • 缺点:当大量key超出过期时间后未被使用,会占用大量内存

    2、定时删除

    由于惰性删除策略无python法保证冷数据被及时的删掉,所以Redis会定期(默认每100ms)主动淘汰一批已过期的key,这里的一批只是部分过期的key,所以可能会出现部分key已经过期但是还没有被清理掉的情况,导致内存没有被及时释放

    简而言之:每隔一定时间删除

    在设置key的过期时间时设置定时器,当key过期时通过定时器删除key。

    • 优点:保证过期的key被及时删除。
    • 缺点:在key过多时,删除key会占用cpu资源,对服务器的响应时间和吞吐量造成影响。同时为每个key设置定时器有性能消耗

    3、定期删除

    redis默认每隔100ms就随机抽取一些设置了过期时间的key,检查其是否过期,如果有过期就删除。注意这里是随机抽取的。为什么要随机呢?你想一想假如 redis 存了几十万个 key ,每隔100ms就遍历所有的设置过期时间的 key 的话,就会给 CPU 带来很大的负载

    简而言之:随机每隔一定时间删除

    定时删除和惰性删除的这种方案,每隔一段时间检查redis中过期的key,并通过限制删除执行的时长和频率。

    • 优点:删除key时限制了删除操作的时长和频率,减少了对CPU的影响。即使删除了过期key,减少了内存的占用。
    • 缺点:如果定期删除太频繁,或者执行时间太长,会退化为定时删除,占用CPU资源。如果删除执行时间太短,或者执行频率低,会退化为惰性删除,出现内存浪费。

    Redis使用的是定期删除+惰性删除的策略,在合理使用CPU和避免内存浪费之间平衡

    定期删除+惰性删除存在的问题

    如果某个key过期后,定期删除没删除成功,然后也没再次去请求key,也就是说惰性删除也没生效。这时,如果大量过期的key堆积在内存中,redis的内存会越来越高,导致redis的内存块耗尽。那么就应该采用内存淘汰机制

    二、内存淘汰机制

    ​​​1、内存淘汰策略

    Redis Key没设置过期时间为什么被Redis主动删除了?

    当Redis已用内存超过maxmemory限定时,就会触发主动清理策略

    在 redis.conf 中有一行配置:

    # maxmemory-policy noeviction

    Redis的默认淘汰策略是noeviction

    执行流程如下

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

    主动清理策略在Redis4.0之前一共实现了8种内存淘汰策略

    a)针对设置了过期时间的key做处理:

    • 1、volatile-ttl:在设置了过期时间的键值对中,移除即将过期的键值对。
    • 2、volatile-random:在设置了过期时间的键值对中,随机移除某个键值对。
    • 3、volatile-lru:在设置了过期时间的键值对中,移除最近最少使用的键值对。
    • 4、volatile-lfu:在设置了过期时间的键值对中,移除最近最不频繁使用的键值对

    b)针对所有的key做处理:

    • 5、allkeys-random:在所有键值对中,随机移除某个key。
    • 6、allkeys-lru:在所有的键值对中,移除最近最少使用的键值对。
    • 7、allkeys-lfu:在所有的键值对中,移除最近最不频繁使用的键值对

    c)不处理:

    • 8、noeviction:不进行淘汰数据。不会删除任何数据,拒绝所有写入操作并返回客户端错误信息"(error) OOM command not allowed when used memory",此时Redis只响应读操作

    一旦缓存被写满,再有写请求进来,Redis就不再提供服务,而是直接返回错误。Redis 用作缓存时,实际的数据集通常都是大于缓存容量的,总会有新的数据要写入缓存,这个策略本身不淘汰数据,也就不会腾出新的缓存空间,我们不把它用在 Redis 缓存中

    ​​​2、内存淘汰算法

    从内测淘汰策略分类上,我们可以得知,除了随机删除和不删除之外,主要有两种淘汰算法:LRU 算法和 LFU 算法

    • LRU算法(Least Recently Used,最近最少使用):淘汰很久没被访问过的数据,以最近一次访问时间作为参考
    • LFU算法(Least Frequently Used,最不经常使用):淘汰最近一段时间被访问次数最少得数据,以次数作为参考

    绝大多数情况,使用LRU算法,当存在大量热点缓存数据时,LFU可能更好点

    三、Lazy-Free机制

    Lazy-Free 特性是 Redis 4.0 开始引入的,指的是让 Redis 采用异步方式延js迟释放 key 使用的内存,将该操作交给单独的子线程处理,避免阻塞主线程

    目的是减少删除键时对主线程的影响,从而提高 Redis 的整体性能。

    Lazy Free 主要有两种应用场景:

    • 主动删除:使用 UNLINK 命令代替 DEL 命令来删除键。UNLINK 命令会在后台异步地释放内存
    • 被动删除:在某些情况下,如过期键的删除或达到最大内存限制时的缓存淘汰,Redis 会尝试异步地释放内存。

    Lazy Free 与缓存淘汰的关系

    虽然 Lazy Free 不是缓存淘汰机制的一部分,但在缓存淘汰过程中,Lazy Free 可以用来优化缓存淘汰操作的执行方式,减少对 Redis 性能的影响。具体来说:

    1、减少主线程阻塞:

    在缓存淘汰策略中,当 Redis 需要删除键来释放内存时,使用 Lazy Free 可以减少主循环的阻塞时间。这是因为删除操作是在后台线程中完成的,而不是立即执行

    2、提高性能:

    Lazy Free 可以帮助提高 Redis 的性能,特别是在高负载的情况下,因为它减少了删除操作对主线程的影响。

    3、与缓存淘汰策略的交互:

    当 Redis 需要根据缓存淘汰策略删除键时,如果启用了python Lazy Free,那么这些删除操作可能会被异步执行,这有助于减少对客户端请求的延迟影响

    例子:假设 Redis 的缓存淘汰策略配置为 allkeys-lru,并且启用了 Lazy Free

    当 Redis 达到最大内存限制时,它会根据 LRU 策略选择一些键来删除。

    如果这些键满足 Lazy Free 的条件(例如,使用了 UNLINK 命令或配python置了相应的 Lazy Free 选项),那么这些键的删除操作将在后台异步执行,而不是立即在主线程中执行

    也就是说如果没有Lazy Free,执行缓存淘汰策略时,删除键的操作将会同步执行,可能会阻塞主线程,影响其他客户端的请求

    四、相关问题

    好了,来解决上面抛出的问题

    1:Redis 给缓存数据设置过期时间?

    (1)Redis的内存是有限的

    • 如果不对缓存数据设置过期时间,那内存占用就会一直增长,最终可能会导致 OOM 问题。
    • 通过设置合理的过期时间,Redis 会自动删除暂时不需要的数据,为新的缓存数据腾出空间

    (2www.devze.com)某些业务场景需要某些数据在一段时间后过期

    • 比如我们的短信验证码可能只在 1 分钟内有效,用户登录的 Token 可能只在 1 天内有效
    • 如果使用传统的数据库来处理的话,一般都是自己判断过期,这样更麻烦并且性能要差很多

    2:Redis 是如何判断数据是否过期的呢?

    • Redis 通过一个叫做过期字典(可以看作是 hash 表)来保存数据过期的时间。过期字典的键指向 Redis 数据库中的某个 key(键)
    • 过期字典的值是一个 long类型的整数,这个整数保存了 key 所指向的数据库键的过期时间(毫秒精度的 Unix 时间戳)
    • 在查询一个 key 的时候,Redis 首先检查该 key 是否存在于过期字典中(时间复杂度为 O(1)),如果不在就直接返回,在的话需要判断一下这个 key 是否过期,过期直接删除 key 然后返回 null。

    3:大量 key 集中过期怎么办?

    如果存在大量 key 集中过期的问题,可能会使 Redis 的请求延迟变高。可以采用下面的可选方案来应对:

    • 尽量避免 key 集中过期,在设置键的过期时间时尽量随机一点。
    • 对过期的 key 开启 lazyfree 机制(修改 redis.conf 中的 lazyfree-lazy-expire参数即可),这样会在后台异步删除过期的 key,不会阻塞主线程的运行。

    总结

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

    0

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    关注公众号