volatile-ttl 不精准淘汰“马上过期”的 key,仅在内存达限且有写入时,从已设 ttl 的 key 中随机采样(默认 20 个),淘汰其中剩余 ttl 最小者;它不全量扫描、不主动清理、不保证命中濒死 key。

volatile-ttl 并不精准淘汰“马上过期”的 key —— 它只是在内存不足时,从已设 TTL 的 key 中随机采样、再挑出剩余 TTL 最小的那一个,仅此而已。
volatile-ttl 的触发条件极其苛刻
它不是后台定时器,也不扫描全量 keys。只有两个条件同时满足才会启动:
-
maxmemory已配置且 Redis 实际内存使用 ≥ 该阈值 - 当前有写入操作(如
SET、LPUSH)触发freeMemoryIfNeeded()
换句话说:key 剩 100ms TTL,但内存没满、也没写入,volatile-ttl 就完全不干活。你查 INFO memory 里的 evicted_keys,很可能一直是 0。
volatile-ttl 的“最短 TTL”是采样得来的,不是全量排序
每次触发时,Redis 默认只随机抽取 20 个设置了 TTL 的 key(由 ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP 控制),然后从中选 TTL 最小的那个淘汰。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 如果这 20 个里恰好没有你认为“最濒死”的 key,它就不会被选中
-
TTL命令返回-2表示该 key 已逻辑过期(在expires字典里但还没物理删除),它会被跳过——volatile-ttl只处理TTL > 0的 key - 即使你用
EXPIREAT精确设了毫秒级过期时间,Redis 内部仍以秒级精度参与比较(除非用PEXPIREAT+redis.conf开启precision-ttl,但该选项未进入稳定版)
为什么你查不到“马上过期”的 key?
因为 Redis 根本不维护“即将过期 key 的优先队列”。redisDb.expires 是个哈希表,键是 key 名,值是绝对过期时间戳——无序、无索引、不预计算剩余 TTL。
- 所有“精准清理”预期,都源于误以为这个字典支持 O(1) 查最小 TTL
-
TTL keyname返回值必须是正整数才参与volatile-ttl竞争;返回-1(无过期)或-2(已过期)的 key 都直接出局 - 业务中若大量 key 的
EXPIRE时间集中在同一秒(比如批量刷新 token),可能连续淘汰一批TTL ≈ 0的 key,但这只是巧合,不是机制保障
真正能提升“濒死 key 清理概率”的实操动作
想让快过期的 key 更早被清理,只能绕开 volatile-ttl 的被动性:
- 调高
hz配置(如从默认 10 改为 100),让activeExpireCycle()更频繁执行定期删除,提高抽中快过期 key 的机会 - 用
PEXPIREAT统一设置毫秒级绝对过期时间点,再配合业务层定时任务跑SCAN+TTL主动DEL剩余TTL 的 key(注意别用 <code>KEYS) - 改用
volatile-lfu或volatile-lru,至少避免长期不访问的濒死 key 占着内存不放
最容易被忽略的一点:volatile-ttl 的“ttl”是运行时动态计算的差值,不是存储在某个有序结构里的静态字段——你无法靠任何命令或监控实时拿到它内部正在比较的那个“最小 TTL 值”。










