Redis集群不负责过期管理,各节点独立清理;需调高hz(建议100)和active-expire-effort(建议10),并排查被动删除盲区、验证多节点清理效果,注意系统定时器精度与CPU争抢问题。

Redis集群里过期Key不自动删干净?别怪集群,先看单节点配置
Redis集群本身不管理过期逻辑,每个节点独立执行过期清理。所谓“集群没删Key”,八成是某个分片(shard)上 hz 太低、或 active-expire-effort 不够,导致后台扫描太懒散。
默认 hz 10 意味着每秒最多做10次过期扫描,每次只检查少量样本(默认20个key)。如果过期Key密集、QPS又高,很容易积压——你看到的“大量过期Key残留”,其实是还没轮到它被扫描到。
-
hz建议调到100(上限),但注意:值越高,CPU占用越明显,尤其在小内存/高负载节点上可能引发抖动 - 必须在每个集群节点的
redis.conf里改,改完redis-cli -p <port> config rewrite</port>或重启生效 - 别只调
hz,顺手把active-expire-effort 10(默认1)也加上,它控制每次扫描时检查的数据库数量,对多DB场景更关键
为什么改了hz还是有Key没删?检查是否命中“被动删除”盲区
Redis过期靠两套机制:主动扫描(hz驱动) + 被动删除(访问时触发)。集群环境下,被动删除容易失效——比如某个Key过期了,但没人再查它,又没被主动扫到,就一直挂着。
常见盲区场景:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 业务用
SCAN遍历key,但跳过了已过期key(Redis 7+才默认在SCAN中过滤过期key;老版本会返回,但GET返回nil) - 使用了
keys *这种阻塞命令,它不触发过期检查,且在集群里根本不能用(报CROSSSLOT错误) - 客户端缓存了key存在性判断(比如先
EXISTS再GET),而EXISTS在key过期瞬间仍返回1,导致后续逻辑跳过清理
集群模式下如何安全验证过期Key清理效果?
不能只看单个节点的 INFO keyspace,因为key分布不均。得逐节点确认,且避开slot迁移干扰。
- 用
redis-cli -c -h <host> -p <port> info keyspace</port></host>分别查每个master节点,重点看db0:keys=100,expires=5这类字段里的expires数是否持续下降 - 临时启用
redis-cli --stat观察expired_keys计数器每秒增量,比肉眼看INFO更灵敏 - 避免在slot迁移期间测——迁移中节点会暂停主动过期任务,
INFO stats里expired_keys可能停涨
hz调太高反而卡住?留意Linux定时器精度和CPU争抢
hz 100 看似合理,但在某些云主机或容器环境里,系统级定时器精度不足(比如 CLOCK_MONOTONIC 实际分辨率只有10ms),会导致Redis频繁忙等,反吞CPU。
- 用
cat /proc/sys/kernel/timer_migration查是否禁用timer migration(应为0);cat /proc/timer_list | head -20看当前jiffies精度 - 观察
INFO cpu中used_cpu_sys是否异常飙升,若 > 0.8(单核)且伴随延迟毛刺,大概率是hz和系统调度打架 - 保守方案:先设
hz 50+active-expire-effort 5,再根据expired_keys每秒处理量微调
真正难搞的是那种写入后立刻过期、又几乎不读的key——它完全依赖主动扫描。这时候光调参数不够,得从源头控制:比如用 PEXPIREAT 替代 EXPIRE 避免时钟漂移误差,或者干脆用 Stream + 消费者TTL替代短时缓存。


















