Redis 过期键的删除策略和内存淘汰机制

Redis 作为最流行的内存数据库之一,其高性能的核心在于数据全部存储在内存中。但内存资源有限,如何管理过期数据和内存不足时的数据淘汰,就成了 Redis 必须解决的关键问题。这也是面试中高频出现的考点,下面我们系统梳理一下。

一、过期键的删除策略

当我们使用 EXPIREPEXPIREEXPIREAT 等命令给键设置过期时间后,Redis 并不会立即删除这些键,而是采用了一套组合策略来平衡 CPU 和内存的消耗。

1. 定时删除(立即删除)

思路:在设置键过期时间的同时,创建一个定时器,到时间就立即删除该键。

优点:内存释放最及时,过期键不会占用内存。

缺点:如果过期键很多,删除操作会占用大量 CPU 时间,影响 Redis 的响应速度和吞吐量。定时器本身也需要消耗系统资源。

结论:Redis 没有采用这种策略。

2. 惰性删除(被动删除)

思路:键过期后不主动删除,只有当客户端访问该键时,才检查是否过期,若过期则删除并返回空。

优点:对 CPU 时间友好,删除操作只在访问时发生,不会浪费 CPU 去检查无关的键。

缺点:对内存不友好。如果一个键已经过期但一直不被访问,它会一直占用内存,造成内存泄漏。

实现:Redis 在 db.c 中的 expireIfNeeded 函数实现惰性删除,所有读写命令在执行前都会调用它。

3. 定期删除(主动删除)

思路:每隔一段时间,程序就对数据库进行一次检查,随机删除一部分过期键。这是定时删除和惰性删除的折中方案。

优点:通过限制删除操作的执行时长和频率,减少对 CPU 的影响,同时也能及时释放部分内存。

缺点:难以确定删除操作的执行时长和频率。太频繁会消耗 CPU,太少又会导致内存浪费。

Redis 的实现:Redis 默认每秒执行 10 次(hz 配置,默认 10)定期删除任务。每次执行时:

  • 从所有设置了过期时间的数据库中随机抽取 20 个键;
  • 删除其中已过期的键;
  • 如果本次删除的过期键比例超过 25%,则重复上述步骤;
  • 同时有一个时间上限(默认 25ms),避免阻塞主线程。

4. Redis 的最终策略

Redis 实际采用的是 惰性删除 + 定期删除 的组合策略。这样既避免了定时删除的 CPU 压力,又通过定期删除弥补了惰性删除可能导致的内存泄漏问题。

二、内存淘汰机制

即使有了过期键删除策略,当 Redis 内存使用达到 maxmemory 限制时,仍然需要一套内存淘汰机制来决定删除哪些数据。这是面试中另一个重点。

1. 配置参数

redis.conf 中通过 maxmemory 设置最大内存,通过 maxmemory-policy 设置淘汰策略。例如:

maxmemory 2gb
maxmemory-policy allkeys-lru

2. 八种淘汰策略

Redis 提供了 8 种内存淘汰策略,可分为四大类:

(1)不淘汰

  • noeviction:默认策略。当内存不足时,不淘汰任何数据,直接对写命令返回错误(读命令仍可执行)。这保证了数据不丢失,但会导致写服务不可用。

(2)基于过期时间的淘汰

  • volatile-lru:从设置了过期时间的键中,使用 LRU 算法淘汰最久未使用的键。
  • volatile-lfu:从设置了过期时间的键中,使用 LFU 算法淘汰使用频率最低的键(Redis 4.0 引入)。
  • volatile-random:从设置了过期时间的键中,随机淘汰。
  • volatile-ttl:从设置了过期时间的键中,优先淘汰剩余生存时间(TTL)最短的键。

(3)基于所有键的淘汰

  • allkeys-lru:从所有键中,使用 LRU 算法淘汰最久未使用的键。
  • allkeys-lfu:从所有键中,使用 LFU 算法淘汰使用频率最低的键(Redis 4.0 引入)。
  • allkeys-random:从所有键中,随机淘汰。

3. LRU 与 LFU 的区别

  • LRU(Least Recently Used):淘汰最近最久未使用的键。它关注的是“最近一次访问时间”,适合有明显热点数据的场景。
  • LFU(Least Frequently Used):淘汰访问频率最低的键。它关注的是“访问次数”,适合热点数据相对稳定的场景。LFU 能避免偶发的一次访问就把冷数据“救活”的问题。

4. Redis 的近似 LRU 算法

标准的 LRU 需要维护一个双向链表,内存开销大。Redis 采用了近似 LRU 算法:

  • 每个对象有一个 24 位的 lru 字段,记录最后一次访问的时间戳。
  • 淘汰时,随机抽取 maxmemory-samples(默认 5)个键,从中选择最久未使用的键淘汰。
  • 抽取的样本数越大,越接近真实 LRU,但 CPU 消耗也越高。

这种设计用很小的内存代价换取了接近 LRU 的效果,是 Redis 在性能和内存之间的经典权衡。

5. 如何选择淘汰策略

  • 如果数据有明显冷热区分,推荐 allkeys-lru
  • 如果数据访问频率差异大且热点稳定,推荐 allkeys-lfu
  • 如果希望只淘汰过期数据,保留永久数据,推荐 volatile-lruvolatile-lfu
  • 如果数据都不能丢失,使用 noeviction 并做好内存监控和告警。

三、总结

维度 过期键删除策略 内存淘汰机制
触发条件 键设置了过期时间且已到期 内存使用达到 maxmemory
核心策略 惰性删除 + 定期删除 8 种策略,常用 allkeys-lru
关注点 CPU 与内存的平衡 内存不足时保留哪些数据

理解这两套机制,不仅能帮助你在面试中从容作答,更能在实际生产环境中合理配置 Redis,避免内存溢出或性能抖动。建议结合 INFO memoryINFO stats 等命令监控 evicted_keysexpired_keys 等指标,做到心中有数。

未经允许不得转载:任鹏个人博客 » Redis 过期键的删除策略和内存淘汰机制

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏