验证PERSIST只清空过期字典不碰值本身,以及被动过期(访问时触发)和主动过期(后台无感知清理)两种机制的工作方式。
Redis用两个独立的字典:一个存key→value,一个专门存key→过期时间戳。
操作SET k1 v1 EX 100 TTL k1 PERSIST k1 TTL k1
结果确认了这一点。
结果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-cli跑出来的原始结果。
TTL / PERSIST / EXISTS / DBSIZE:验证被动与主动过期