开启 notify-keyspace-events 是必要前提,因 redis 默认关闭键空间通知,必须在 redis.conf 中配置 kea 并重启生效;监听淘汰触发的 del 事件需订阅 __keyevent@0__:del 频道;仅靠 del 无法区分自然过期与被动淘汰,需结合 ttl 辅助判断;高频淘汰可借 shell 聚合或 python 脚本统计归因。

为什么开启 notify-keyspace-events 是必要前提
Redis 默认不发送任何键空间事件,keyspace 通知完全关闭。不打开它,后续所有监听行为都收不到信号——不是代码写错,而是根本没通电。必须在 redis.conf 中显式配置,且重启生效,热重载(CONFIG SET)对这个参数无效。
-
notify-keyspace-events值必须包含E(表示过期事件),仅开K或A不行 - 推荐最小安全值是
KEA:K=键空间事件、E=过期事件、A=通用命令事件(含DEL、EXPIRE等) - 路径通常是
/etc/redis/6379.conf,但需确认实际配置文件位置,用redis-cli CONFIG GET notify-keyspace-events校验是否已生效
怎样监听淘汰触发的 DEL 事件
Redis 的“淘汰”本身不发事件,真正能捕获的是淘汰动作落地后的 DEL 操作——即键被真正删除时,会向 __keyevent@<db>__:del</db> 频道推送消息。这是唯一可稳定追踪“哪些 key 刚被淘汰”的实时入口。
- 用
redis-cli --csv SUBSCRIBE '__keyevent@0__:del'订阅 DB 0 的 del 事件(把0换成你的目标 DB 编号) - 注意:如果用了
allkeys-lru等策略,淘汰可能发生在内存压力下主动驱逐,此时也会触发DEL;但若用volatile-ttl且 key 过期时间未到,不会触发 - 输出格式为
"__keyevent@0__:del","some:cache:key",第二个字段就是被淘汰的 key 名
如何区分“自然过期”和“被动淘汰”
仅靠 DEL 事件无法区分是 TTL 到期还是 LRU/LFU 主动淘汰——两者都走同一事件通道。要分离它们,得结合 EXPIREAT 或 TTL 命令做辅助判断:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 在监听到
DEL后,立刻用redis-cli TTL some:cache:key查该 key 的剩余 TTL(需在 key 被删前查,所以得加延迟或用 Lua 脚本原子化) - 如果返回
-2(不存在)或-1(永不过期),基本可判定是allkeys-*类策略淘汰的 - 如果返回正数,说明它本有 TTL,但还没到期就被淘汰了——这往往意味着内存压力大 +
volatile-*策略失准,值得告警
高频淘汰 key 的临时归因技巧
光看单次 DEL 事件意义有限。真正要定位“频繁淘汰”,需要轻量聚合,避免引入外部存储或复杂 pipeline:
- 用
redis-cli --csv SUBSCRIBE '__keyevent@0__:del' | head -n 1000 | cut -d',' -f2 | sort | uniq -c | sort -nr | head -20快速统计最近 1000 次删除中 top 20 key - 注意:该命令依赖 shell 工具链,生产环境建议改用 Python 脚本持续消费 + 内存计数(超时清空),防止内存无限增长
- 如果发现某类 key(如带时间戳后缀的)高频出现,大概率是缓存粒度太细或 TTL 设置不合理,而不是策略本身问题
真正难的不是抓到 key,而是判断它为何被反复淘汰:是业务写入节奏突增?还是淘汰策略与数据访问模式严重错配?比如 volatile-lru 配合大量短 TTL key,会导致 LRU 队列频繁抖动,误杀热点。这种逻辑层关联,没法靠事件监听自动得出。










