用DEBUG SET-ACTIVE-EXPIRE完全禁用后台过期扫描,验证一个逻辑上已过期的key还占用着内存,直到一次GET才触发清理。
Redis有一个周期性运行的后台线程,专门抽查过期的key并删除它们——先把它关掉。
操作DEBUG SET-ACTIVE-EXPIRE 0 -- 完全禁用后台过期扫描 SET k1 v1 PX 100 sleep 1秒(TTL 100ms早就过去了)
没有后台线程来清理,会发生什么。
结果1秒后(TTL早已过期100ms),active-expire已禁用: DBSIZE → :1(key还在!) MEMORY USAGE k1 → :48字节(占用着物理内存)
验证了:一个"逻辑上"早就该消失的key,如果没有任何机制去主动清理它,会一直躺在内存里——TTL 只是给这个key打上了一个"过期时间戳",本身不会触发任何清理动作,得靠别的机制来做这件事。
被动过期(lazy expire)是保底机制。
结果GET k1 → 返回空(nil) DBSIZE → :0(立刻被清理了)
这次的GET访问,触发了Redis的"惰性检查":命令执行前先看一眼这个key的TTL是不是已经过了,过了就先删除它,再假装这个key从来没存在过,返回空结果。这就是为什么哪怕完全没有后台线程,Redis也能保证"你永远不会读到一个已过期的值"——被动过期是的最后一道保险。
正常情况下(不手动关掉它),后台扫描才是主要在工作的机制。
结果DEBUG SET-ACTIVE-EXPIRE 1 -- 恢复后台扫描 SET k2 v2 PX 100 sleep 1秒,完全不访问k2 DBSIZE → :0(自动被清理了,没有任何人访问过它)
每一步都是本文上面用redis-cli跑出来的原始结果。
DEBUG SET-ACTIVE-EXPIRE 0/1:控制后台过期扫描的开关MEMORY USAGE:验证过期key依然占用内存