redis默认采用惰性删除与定期删除协同的过期策略,其中定期删除频率由hz配置项控制,默认10,过高会导致cpu飙升,而惰性删除仅在访问命令中触发,非访问操作如del、keys等会绕过清理,造成过期键堆积和内存压力。

Redis 默认的过期策略(惰性删除 + 定期删除)已经做了基本平衡,但如果你观察到 CPU usage 异常升高、尤其是 redis-server 进程持续占用高 CPU,大概率是定期删除扫描行为在“用力过猛”——不是策略本身有问题,而是配置或使用方式没对齐业务负载。
定期删除频率太高会拖垮CPU
Redis 每秒执行多少次过期扫描,由配置项 hz 控制,默认值是 10(即每 100ms 扫描一次)。但这个值不是静态的:当 Redis 检测到内存中过期键比例较高时,会临时把 hz 提升到最大 100,导致扫描更频繁、更密集。
- 高频扫描会触发大量随机 key 抽样、TTL 判断和删除操作,尤其在
expires字典很大(比如几十万带 TTL 的 key)时,dictGetRandomKeys和removeExpire开销显著上升 -
hz值过高(如人为设为100)会让 Redis 在低流量时段也持续“自检”,白白消耗 CPU - 注意:
hz不是“每秒扫描次数”的硬上限,而是“基准频率”,实际扫描节奏还受activeExpireCycleTryUpTo逻辑限制(每次最多处理 20 个过期 key,且单次耗时不超过 1ms)
惰性删除被绕过时,过期键堆积成内存压力源
惰性删除只在 GET、SETNX、HGET 等访问类命令中触发。如果业务大量使用 DEL、EXISTS、KEYS 或管道批量写入,这些操作**不会检查过期**,也就跳过了惰性清理路径。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
-
DEL key直接删主字典 entry,但不碰expires字典 —— 如果 key 已过期但还没被惰性触发,DEL实际上什么也没删,反而留下一个“已过期但未清理”的残留 -
KEYS *或SCAN不触发任何过期检查,返回结果里可能包含大量已过期 key,误导业务逻辑 - 用
EXPIRE覆盖已有 key 的 TTL 时,旧过期时间会被更新,但若原 key 已过期且尚未被惰性/定期清理,它仍会卡在expires字典里,直到下次扫描
真正影响 CPU 的其实是“过期键密度”和“访问模式”
比起调参数,更关键的是控制哪些 key 该设 TTL、设多久、怎么访问。Redis 的定期删除成本和惰性触发率,直接取决于你往 expires 字典里塞了什么。
- 避免给短期临时 key(如秒级限流计数器)设置长 TTL;用
INCR+EXPIRE组合时,确保EXPIRE成功执行(检查返回值是否为1) - 高频写入场景(如用户 session 刷新),不要反复
SET+EXPIRE,改用SETEX或SET带EX参数——减少一次网络往返和一次 dict 查找 - 批量清理场景(如登出清 session),优先用
SCAN+DEL,而不是KEYS;但注意SCAN不触发惰性删除,所以建议搭配TTL检查后只删TTL > 0的 key,避免误删已过期残留 - 如果业务允许,对冷数据用
volatile-lru淘汰策略替代长 TTL,把“过期判断”交给内存压力触发,而非定时扫描
最隐蔽的 CPU 开销往往来自“过期键没被删干净,又不断新增”,导致 expires 字典持续膨胀、扫描效率下降。定期删除不是魔法开关,它只是配合惰性删除的兜底手段——真正减轻 CPU,靠的是让过期键少一点、轻一点、更容易被扫到。










