Redis 的 Key 到期后,不一定在到期瞬间就完成内存回收。Redis 主要结合访问时检查的惰性删除与后台周期性执行的主动过期,兼顾请求延迟和内存使用。这里讨论 Redis OSS 的常见机制,具体扫描预算和配置应以运行版本为准。
两种策略怎样配合?
惰性删除发生在访问 Key 时。若 Redis 发现它已过期,就按不存在处理并删除,而不是把过期值返回给正常读取请求。这种方式不会为每个 Key 创建独立定时器,但从此无人访问的过期 Key 可能暂时留在内存。
主动过期则定期检查带过期时间的 Key,清理其中已经到期的部分。它有时间预算,避免一次扫描所有 Key 把主线程占满。过期比例较高时可以继续清理,但仍需要在释放内存和服务请求之间做权衡。不能理解为“每隔固定时间检查所有 Key”。
假设一批商品缓存同时到期:访问中的 Key 可由惰性检查清理,无人访问的部分由主动过期逐步回收;如果全部同时失效,数据库仍可能遭遇雪崩。删除策略负责过期数据清理,业务还应给 TTL 加随机量、控制缓存重建并发。
过期和淘汰有什么区别?
| 机制 | 触发原因 | 是否可能删除没到期的数据 |
|---|---|---|
| 过期删除 | 到达 Key 的过期时间 | 按 TTL 判断 |
| 内存淘汰 | 超过 maxmemory 且执行相应策略 | 可以 |
Key 设置了一小时 TTL,并不意味着它一定能存活一小时;采用 allkeys 淘汰策略时,它可能提前被淘汰。反过来,没有 TTL 的 Key 也可能被 allkeys 策略删除。
常见追问
到期但还没回收,GET 会返回旧数据吗?
普通主节点读取会检查过期并按不存在处理。逻辑上不可见和物理内存释放是两件事;副本读取与复制状态等边界需要另行考虑,不能把物理残留当成业务可读保证。
为什么不用精确的定时删除?
为海量 Key 维护定时任务有管理成本,大量同时到期还会集中消耗 CPU。惰性和主动检查让清理工作分摊到访问与后台执行。
DEL 与 UNLINK 对过期策略有什么影响?
它们是主动删除命令,不能替代自动过期机制。UNLINK 将 Key 从键空间摘除,并把适合异步释放的工作交给后台;小对象释放未必总交给后台。对大对象的删除延迟应实测。
TTL 到期通知能作为可靠的定时任务吗?
不能。键空间通知不是可靠消息队列,事件产生时间也受实际过期清理时机影响。订单超时等业务需要可恢复的调度或消息机制。