过期key清理不及时本质是默认配置保守:hz=10导致每100ms仅扫描20个key且耗时受限,叠加active-expire-effort过小和被动删除未触发,造成积压。

过期 Key 清理不及时,本质不是 Redis “不干活”,而是默认配置太保守——hz 太低、active-expire-effort 太小、被动删除又没触发,三者叠加就导致内存悄悄涨满。
为什么 hz 设为 10 会导致大量过期 Key 积压
Redis 每秒只执行 hz 次后台任务,其中一项就是扫描过期 Key。默认 hz 10 意味着:每 100ms 才扫一次,每次只随机检查 20 个带过期时间的 key(由 ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP 控制),删完如果发现超 25% 已过期,才重复一轮——但最多只花 25ms。
这在低频缓存场景够用,但在以下情况会明显跟不上:
- 批量写入短 TTL key(如每秒 5k 个 5 秒 token),过期集中在同一窗口
- 业务使用
SCAN遍历 key,但老版本 Redis 不在SCAN中过滤过期 key,导致应用误以为 key 还存在 - 客户端缓存了
EXISTS结果,而EXISTS在 key 过期瞬间仍返回1,跳过后续清理逻辑
怎么调 hz 和 active-expire-effort 才有效
单纯改 hz 不够,必须同步调高 active-expire-effort(Redis 4.0+ 引入,控制每次扫描的数据库数量),否则只是“更频繁地扫同一个库”。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 在每个节点的
redis.conf中加两行:hz 100<br>active-expire-effort 10
- 运行时生效(需 Redis ≥ 5.0):
CONFIG SET hz 100<br>CONFIG SET active-expire-effort 10
- 改完必须执行
CONFIG REWRITE或重启,否则仅本次生效 - 注意:
hz超过 100 后 CPU 占用上升明显,云主机或容器中可能因系统定时器精度不足(如只有 10ms 分辨率)反而引发忙等,实测建议先从 50 起步观察
如何验证清理是否真正变快,而不是参数“看起来改了”
别只信 CONFIG GET hz,重点看指标变化:
- 用
redis-cli -p <port> info stats | grep expired_keys</port>查每秒新增数:调大后应更平滑,尖峰下降 - 对比
used_memory_peak_human和used_memory_human差值:差值收窄说明内存释放更及时 - 监控
evicted_keys是否上涨——如果因hz过高挤占主线程,导致请求堆积、触发 LRU 驱逐,就得回调 - 集群下必须逐节点查:
redis-cli -c -h node1 -p 6379 info keyspace,看各db0:expires=是否持续下降,避开 slot 迁移窗口期
比调参更关键的盲区:被动删除根本没机会触发
定期删除再勤快,也救不了那些“没人碰”的过期 key。常见被动失效场景:
-
KEYS *在集群模式下直接报CROSSSLOT错误,根本走不到过期检查 - 业务用
SCAN+GET做批量读,但 Redis 6 及以前版本的SCAN默认返回已过期 key(GET才返回nil),导致应用逻辑漏删 - 从库上读取过期 key:从库不主动删,只靠主库同步
DEL,若主从延迟大,从库内存里就挂着一堆“逻辑过期但物理未删”的 key
真正卡住的地方,往往不在参数数字,而在这些被动路径是否被业务代码无意绕开——比如用 EXISTS 判断 key 存在性后直接跳过 GET,等于主动屏蔽了惰性删除入口。










