过期删除和内存淘汰是两套完全独立的机制,前者处理带过期时间的key(定期扫描+惰性检查),后者在内存达maxmemory阈值时按策略淘汰key,二者不互相触发、也不互相替代。

过期删除和内存淘汰是两套完全独立的机制,不互相触发、也不互相替代。一个管“时间到了该删”,一个管“内存满了必须删”。
过期删除策略:只处理带 expires 字段的 key
Redis 不会在 key 到期瞬间就删掉它,而是靠「定期扫描 + 惰性检查」配合清理:
-
定期删除:默认每 100ms 执行一次,随机从每个 DB 的过期字典中抽 20 个 key 检查是否过期;如果其中 ≥25% 已过期,会再抽一轮,但单次耗时不能超过 CPU 时间的 25%(hz越高,单次允许耗时越短) -
惰性删除:每次执行GET、SET等命令访问 key 前,先查它是否在过期字典里、且当前时间已超expireat,是则立刻删并返回 nil - 没被抽中、也没被访问的过期 key 会一直留在内存里——这就是为什么
TTL返回 -2 时,key 实际已过期但还没删干净 -
EXPIRE、PEXPIRE、EXPIREAT、PEXPIREAT和SETEX/SET的ex/px参数设置的都是同一套过期逻辑,底层全转成PEXPIREAT
内存淘汰策略:只在 maxmemory 触发后才生效
当 Redis 内存使用量 ≥ maxmemory 配置值时,写操作(如 SET)才会触发淘汰。它不管 key 是否过期,只看当前内存压力:
Redis 8.2.3 是一款安全优先的高性能键值存储系统。该版本紧急修复了可能引发远程代码执行(RCE)的高危漏洞(CVE-2025-62507),并解决了 HyperLogLog 及 Cuckoo Filter 等数据结构在特定场景下的崩溃问题。建议所有用户立即升级,以保障生产环境的系统稳定与数据安全。
-
noeviction(默认):拒绝所有写入,返回(error) OOM command not allowed when used memory;读操作照常 - 选
volatile-*类策略时,只对设置了过期时间的 key 生效;allkeys-*则对全部 key 生效 -
volatile-ttl是唯一按「剩余 TTL」排序的策略,适合缓存分层场景(比如把 1min 后就过期的 key 优先踢掉) -
allkeys-lru和allkeys-lfu是最常用的选择,前者适合访问模式有明显时间局部性,后者适合热点分布稳定但时间跨度大的场景 - 注意:
LRU和LFU在 Redis 中都是近似算法(采样 5 个 key 比较),不是严格实现,所以不要指望它精准淘汰“最久未用”的那个
maxmemory 和 maxmemory-policy 必须配对设置
光设 maxmemory 不设 maxmemory-policy,等于开了闸门却不装水阀——内存一满就直接报错写失败:
- 用
CONFIG SET maxmemory 2gb设置上限后,必须紧接着CONFIG SET maxmemory-policy allkeys-lru,否则新写入会失败 -
maxmemory建议设为物理内存的 70%~80%,留出空间给 Redis 自身开销(如复制缓冲区、AOF rewrite 临时文件) - 如果业务大量使用带过期时间的 key,建议优先选
volatile-lru或volatile-ttl;如果 key 大部分没设过期时间(比如持久化 session),只能选allkeys-*类策略 -
CONFIG GET maxmemory和CONFIG GET maxmemory-policy可随时验证当前配置,别依赖 redis.conf 里的注释行
最容易被忽略的是:过期 key 在内存里“躺平”期间,既不计入 used_memory 的活跃数据统计,也不触发淘汰——它只等定期扫描或下一次访问。这意味着,如果你的业务写入大量短期缓存但几乎不读,INFO memory 里的 mem_fragmentation_ratio 可能正常,但 expired_keys 计数器会持续上涨,最终拖慢定期扫描速度。










