bigywater.tech
Redis · 15

Key 过期字典

验证PERSIST只清空过期字典不碰值本身,以及被动过期(访问时触发)和主动过期(后台无感知清理)两种机制的工作方式。

两套独立字典
值和过期时间分开存储
被动过期
访问时才发现并清理
主动过期
无需访问也会被后台清理

做的事:验证过期信息是独立存的,不是主键值的一部分

Redis用两个独立的字典:一个存key→value,一个专门存key→过期时间戳。

操作SET k1 v1 EX 100 TTL k1 PERSIST k1 TTL k1

验证:PERSIST只清空过期字典里的记录,不碰值本身

结果确认了这一点。

结果SET k1 v1 EX 100 TTL k1 → 100 PERSIST k1 TTL k1 → :-1(永不过期) GET k1 → :v1(值完全没变)

验证了:PERSIST 只是把这个key从"过期字典"里删掉,主键值字典里的k1、v1完全没有被动过。这也印证了Redis内部是两套独立的哈希表:一套是所有key真正的数据,另一套只记录"哪些key、什么时候过期",两者靠key名字关联,但是分开存储、分开维护的。

验证:被动过期——访问时才发现并清理

给一个key设200毫秒过期,故意等到超时之后再去碰它。

结果SET k3 v3 PX 200 sleep 300毫秒(超过了200毫秒的TTL) EXISTS k3 → :0 GET k3 → :nil

k3在逻辑上早已经过期了,但如果没人来访问它,它不会立刻从内存里消失。测试里,EXISTS/GET这次访问触发了Redis的"惰性检查":发现这个key的过期时间已经过了,就在这次访问时把它删除,并对外表现得像它从来不存在过——这就是被动(惰性)过期。

验证:主动过期——完全不访问,也会被后台清理

这次设置一个key过期,中途完全不去访问它,只看DBSIZE的变化。

结果SET k4 v4 PX 100 DBSIZE → 3(此时k4还没过期) sleep 500毫秒(完全不访问k4) DBSIZE → :2(k4消失了,但没有任何显式访问触发它)

整个过程没有对k4做任何读写操作,但DBSIZE还是从3降到了2——这证明Redis有一个在后台周期性运行的主动过期机制,会定期从过期字典里随机抽查一批key,检查是否已过期,过期就主动删除,不需要等到有人访问才发现。

两种过期机制配合工作:被动过期保证"哪怕后台没扫到,访问的时候一定不会读到过期数据";主动过期保证"哪怕永远没人访问,过期数据也不会永远占着内存不放"。过期字典的存在,让Redis可以高效地只遍历"设了TTL的那部分key"去做主动清理,而不用扫描整个数据库。

分步演示:过期字典是怎么工作的

每一步都是本文上面用redis-cli跑出来的原始结果。

过期字典独立于主键值,被动+主动两种清理方式
这一步新验证的机制

    本文用到的工具

    • 本机 Redis 8.10.1 单节点
    • TTL / PERSIST / EXISTS / DBSIZE:验证被动与主动过期
    京ICP备2026067502号-1京公网安备11010502063487号