Redis Key 过期后会立刻删除吗?过期删除与内存淘汰策略详解

发布时间:2026/6/1 17:12:11

Redis Key 过期后会立刻删除吗?过期删除与内存淘汰策略详解 Redis 里的 key 可以设置过期时间但 key 到期并不意味着会被立刻删除。Redis 需要在 CPU 成本和内存释放之间做平衡所以采用的是惰性删除 定期删除。当内存真的不够用时Redis 还会根据内存淘汰策略删除一部分 key。这篇把两个问题放在一起讲key 过期后怎么删除内存满了以后怎么淘汰一、惰性删除访问时才检查惰性删除的意思是设置了过期时间后Redis 不会一直盯着这个 key。只有当客户端访问这个 key 时Redis 才检查它是否过期。优点是对 CPU 友好因为 Redis 不需要为每个过期 key 立刻做检查。缺点是对内存不友好如果一个 key 已经过期但再也没人访问它它可能会继续占在内存里。二、定期删除周期性抽样清理为了避免过期 key 一直占内存Redis 会定期抽取一部分 key 检查并删除过期数据。定期清理有两种模式模式特点SLOW定时任务默认 10hz每次不超过 25msFAST执行频率不固定两次间隔不低于 2ms每次不超过 1ms定期删除的优点是可以主动释放内存同时通过限制时长和频率减少对 CPU 的影响。缺点是很难精确控制执行频率太频繁会影响 CPU太少又会让过期 key 占用内存。所以 Redis 最终采用组合策略Redis 过期删除策略 惰性删除 定期删除三、内存满了怎么办过期删除解决的是“已经设置 TTL 的 key 到期后怎么清理”。但如果 Redis 内存已经满了新的写入进来怎么办这就涉及内存淘汰策略。Redis 会按照配置的规则选择一部分 key 删除。四、Redis 的 8 种淘汰策略策略作用范围淘汰规则noeviction不淘汰内存不足时新写入直接报错volatile-ttl设置了 TTL 的 key剩余 TTL 越小越先淘汰allkeys-random全体 key随机淘汰volatile-random设置了 TTL 的 key随机淘汰allkeys-lru全体 key淘汰最近最少使用volatile-lru设置了 TTL 的 key淘汰最近最少使用allkeys-lfu全体 key淘汰访问频率最低volatile-lfu设置了 TTL 的 key淘汰访问频率最低默认策略是noeviction也就是内存不足时不删除任何数据新写入会报错。五、LRU 和 LFU 的区别LRU是Least Recently Used最近最少使用。它看的是“多久没被访问过”。当前时间 - 最后一次访问时间 越大越优先淘汰LFU是Least Frequently Used最少频率使用。它看的是“访问次数多不多”。访问频率越低淘汰优先级越高简单理解LRU 更关注最近有没有用LFU 更关注长期用得多不多。六、开发中怎么选业务特点推荐策略有明显冷热数据allkeys-lru访问频率差别不大allkeys-random有置顶数据不能淘汰volatile-lru置顶 key 不设置 TTL短时高频访问明显allkeys-lfu或volatile-lfu不允许 Redis 自动删数据noeviction面试里经常会问“数据库有 1000 万数据Redis 只能缓存 20 万怎么保证 Redis 里都是热点数据”可以回答使用allkeys-lru或allkeys-lfu让 Redis 自动淘汰不常访问的数据留下更热的数据。七、深入分析策略背后的权衡与调优前面的章节介绍了 Redis 过期删除和内存淘汰的“是什么”和“怎么选”。这一节我们来深入探讨一下“为什么”——即这些策略背后的设计哲学、潜在问题以及生产环境中的调优思路。7.1 惰性删除与定期删除的深层权衡Redis 选择“惰性删除 定期删除”的组合本质上是空间内存与时间CPU的经典权衡。纯惰性删除的极端情况想象一个场景一批用于临时会话的 key 在凌晨3点同时过期但此后再也没有被访问。在纯惰性删除策略下这些“僵尸 key”会一直占用内存直到 Redis 重启或内存淘汰被触发。这可能导致内存使用率虚高甚至引发不必要的淘汰。纯定期删除的挑战如果试图通过提高定期删除的频率和力度来立刻清理所有过期 key会显著增加 CPU 开销在 key 数量巨大时可能影响主线程处理正常命令的延迟违背 Redis 高性能的初衷。生产启示监控expired_keys指标。如果这个值增长缓慢而used_memory持续高位可能意味着有过期 key 堆积需要考虑调整hz配置控制定期删除频率或在业务层确保对已过期的 key 有访问清理机制。7.2 内存淘汰策略的算法实现与近似性需要明确的是Redis 实现的 LRU 和 LFU 都是近似算法而非精确实现。Redis LRU并非维护一个全局的精确访问时间链表那会带来巨大开销而是对每个 key 采样一个 24 位的“空闲时间idle time”戳。淘汰时从采样池中选出空闲时间最长的 key 进行淘汰。这是一种概率性 LRU在保证性能的同时大体上能淘汰掉最久未使用的数据。Redis LFU使用 Morris 计数器来近似统计访问频率并且设计有衰减机制lfu-decay-time防止早期高频访问的 key 永久驻留。这比简单的访问计数更智能能适应访问模式的变化。生产启示理解其近似性很重要。allkeys-lru不能保证绝对淘汰最旧的但能很好地维护热数据集。对于要求极高的场景可能需要业务层自己实现更精确的缓存管理如二次缓存、本地缓存等。7.3 配置maxmemory-policy的实践细节volatile-xxx策略的陷阱如果使用volatile-lru、volatile-lfu或volatile-random但 Redis 实例中没有 key 设置 TTL那么当内存满时这些策略将无 key 可淘汰效果会退化成noeviction导致写入错误。务必确保有足够多的 key 设置了过期时间。allkeys-lru与持久化如果使用allkeys-lru且开启了 RDB 或 AOF 持久化被淘汰的 key 虽然从内存中删除但可能仍然存在于持久化文件中在下次重启加载时会被重新载入内存。这可能导致重启后内存瞬间打满。需要评估是否有必要对持久化文件进行清理。监控指标关注evicted_keys被淘汰的 key 总数和used_memory。evicted_keys的突然飙升是内存压力的明确信号。7.4 超越内置策略架构层面的思考当内置策略无法满足需求时可以考虑架构升级拆分实例将不同类型、不同重要性的数据存放到不同的 Redis 实例中并配置不同的maxmemory和淘汰策略。例如用户会话数据使用allkeys-lru而重要的配置数据使用noeviction并存放在独立的小内存实例中。使用 Redis 4.0 的模块或新数据结构例如对于可容忍丢失的缓存数据可以考虑使用RedisBloom模块的布隆过滤器先进行一层过滤减少无效 key 的存储。客户端策略在客户端实现本地缓存如 Guava Cache、Caffeine并设置更短的 TTL 和大小限制形成多级缓存体系减轻 Redis 层的压力和淘汰的敏感性。7.5 面试深度问题示例“Redis 的 LRU 算法和传统 LRU 有什么区别”答Redis 使用的是近似 LRU。它通过随机采样一批 key并淘汰其中空闲时间最长的 key而不是维护一个全局的精确链表。这在性能和效果上取得了很好的平衡虽然不绝对精确但实践表明足以很好地维护热数据集合。“如何发现和解决 Redis 中过期 key 大量堆积的问题”答首先通过INFO命令观察expired_keys的增长是否与预期相符以及used_memory是否异常高。若存在堆积可尝试① 调高hz配置增加定期删除频率② 检查业务代码确保对设置了过期时间的 key 有后续的访问或清理逻辑③ 对于已知会批量过期的 key可以考虑将其过期时间加上随机抖动避免同时过期。“在使用了allkeys-lru的 Redis 中为什么有时最近访问的数据还是被淘汰了”答因为 Redis 的 LRU 是近似的。在内存压力极大、key 更新极快的场景下采样过程可能无法总是捕捉到最新的访问模式。此外如果所有 key 的访问都非常频繁LRU 的“最近最少使用”判据也会变得模糊。此时可以评估是否切换为allkeys-lfu或考虑扩容内存。七、总结Redis key 过期不会立刻删除而是惰性删除和定期删除配合内存不够时才会触发淘汰策略。平时开发最常用的是allkeys-lru能让最近常访问的数据尽量留在缓存里。

相关新闻