object idletime 返回 key 自上次访问以来经过的 lru 时钟单位数,单位默认为1秒,是 server.lruclock 与 redisobject.lru 的模差值;返回值为近似值,已过期 key 返回-2,不存在 key 返回-1。

OBJECT IDLETIME 返回的是什么时间
OBJECT IDLETIME 命令返回的不是绝对时间戳,也不是 Unix 秒数,而是该 key 自上次被访问以来,**经过了多少个 LRU 时钟单位(LRU clock ticks)**。这个值本质上是当前全局 server.lruclock 和 key 对应 redisObject.lru 字段的差值(取模后处理),单位由 LRU_CLOCK_RESOLUTION 决定,默认为 1 秒。
这意味着:OBJECT IDLETIME key 返回 120,代表该 key 至少空闲了约 120 秒 —— 但不精确到毫秒,也不排除因时钟回绕导致的小偏差。
- 该命令只对存在且未过期的 key 有效;对已过期但尚未被惰性/定期删除的 key,返回
-2 - 对不存在的 key,返回
-1 - 返回值是近似值,因为
lruclock每秒只更新一次(由serverCron驱动),且lru字段本身是 24 位无符号整数,最大值为LRU_CLOCK_MAX = (1,按 1 秒分辨率算,约 194 天就会回绕
为什么 OBJECT IDLETIME 有时返回 0 却不是刚被访问
返回 0 并不严格等价于“刚刚被访问”,它只表示:当前 server.lruclock 和 key 的 lru 字段值相等(或模运算后相等)。由于 LRU 时钟是离散更新的,多个 key 可能在同一秒内被访问,它们的 lru 值就完全一样。
更关键的是:Redis 不会在每次读写都刷新 lru 字段。只有在满足以下任一条件时才会更新:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 执行了读操作(如
GET、HGET等),且该 key 的lru值 ≠ 当前server.lruclock - 执行了写操作(如
SET、HSET),此时会强制重置lru为当前server.lruclock -
server.lruclock本身每秒只推进一次,所以即使你高频访问一个 key,在同一秒内多次访问也只会记录一次更新
如何结合 INFO memory 判断是否启用 LRU 类淘汰策略
仅靠 OBJECT IDLETIME 无法反推 Redis 正在用哪种淘汰策略 —— 它只是暴露了底层 LRU 时钟机制,和实际配置的 maxmemory-policy 无直接映射关系。真正决定“哪个 key 会被淘汰”的,是 INFO memory 中的 maxmemory_policy 字段,以及键是否带过期时间。
例如:
- 如果
maxmemory_policy是volatile-lru,那么只有设置了EXPIRE的 key 才参与 LRU 淘汰,OBJECT IDLETIME对这些 key 有意义 - 如果是
allkeys-lru,所有 key 都参与,但OBJECT IDLETIME仍只反映空闲时长,不体现淘汰优先级排序逻辑 - 如果是
noeviction或lfu类策略,OBJECT IDLETIME依然能查,但它对淘汰行为毫无影响 —— LFU 看的是lru字段里编码的访问频次信息,不是空闲时间
容易被忽略的精度与回绕陷阱
24 位 lru 字段 + 1 秒分辨率,意味着时钟每约 194 天回绕一次。当系统运行时间较长(比如 Redis 实例持续运行超半年),就可能出现:一个 key 的 lru 值(比如 1000)比当前 server.lruclock(比如 500)还大 —— 这不是 bug,而是设计使然。Redis 在 estimateObjectIdleTime() 中会做无符号回绕处理,确保差值始终代表“合理”的空闲长度。
但你在业务中若自行用 OBJECT IDLETIME 做缓存老化判断(比如“空闲超 300 秒就删”),要注意:
- 它不能替代 TTL 逻辑,因为不感知过期时间本身
- 它无法区分“刚写入”和“刚被访问”,两者都重置
lru为当前值 - 高并发下多个 key 同一秒被访问,
OBJECT IDLETIME无法分辨细微访问顺序










