client tracking on 开启服务端 key 状态追踪表及缓存失效通知通道,需配合 redirect 或 broadcast 模式、显式读取声明和客户端 push 消息处理才能生效。

Redis 6.0 的 CLIENT TRACKING ON 命令到底开启什么
开启 CLIENT TRACKING ON 并不只是“让客户端能监听 key 变化”,它实际启用的是服务端的 **key 状态追踪表(tracking table)**,并为每个连接维护一个本地缓存失效通知通道。这个机制依赖两个关键前提:客户端必须显式声明自己关心哪些 key(通过读取触发),且服务端需开启响应式广播能力(默认关闭)。
常见错误是只执行 CLIENT TRACKING ON 就以为万事大吉——其实它默认使用 REDIRECT 模式但未指定目标 client id,也不会自动广播失效;更不会感知 LRU/LFU 驱逐事件本身。
- 必须配合
REDIRECT <client-id></client-id>或BROADCAST模式才可能收到通知 -
BROADCAST模式要求 Redis 启动时设置notify-keyspace-events "Ex"(仅限键过期事件)或"Ee"(驱逐事件),但注意:驱逐事件(evicted)在 6.0 中默认不触发 tracking 广播 - 真正能被 tracking 机制捕获并广播的,是服务端主动执行的写操作(如
SET、DEL、EXPIRE),不是内存满后被动淘汰
如何让被 LRU/LFU 驱逐的 key 触发 tracking 失效广播
Redis 6.0 的 tracking 机制本身不监听内存淘汰行为,Ee 事件(evicted)仅在 key 因过期或显式 MEMORY PURGE 被删时发出,而 LRU/LFU 驱逐属于内部内存管理路径,不走事件总线,也不更新 tracking table。
所以想“自动广播被驱逐 key”,必须绕过原生限制:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 用
CONFIG SET maxmemory-policy noeviction关闭自动驱逐,改由应用层控制缓存生命周期(例如加 TTL + 主动清理) - 启用
maxmemory-policy allkeys-lru后,搭配定期执行MEMORY DOCTOR+INFO memory监控evicted_keys计数器,再通过外部脚本扫描最近变更的 key(不可靠) - 最可行的方案:**不依赖驱逐事件,而是统一走写路径**——所有业务写操作都封装为带
DEL前置的原子操作(如 Lua 脚本),确保每次覆盖旧值前先通知订阅端
tracking 广播失效的 key 是怎么确定的
Redis 不会“猜测”哪个 key 应该失效,它只对满足以下全部条件的 key 才记录进 client 的 tracking 表,并在后续写入时触发失效:
- 该 client 在开启 tracking 后,曾执行过对该 key 的只读命令(
GET、HGET、SMEMBERS等) - 该 key 当前存在于 tracking table 中(未被
CLIENT TRACKING OFF或超时清除) - 有其他 client 或本 client 对该 key 执行了**可观察的修改命令**(
SET、DEL、INCR、EXPIRE等),且命令未被跳过(如 pipeline 中的中间命令) - 服务端配置了对应模式:比如
CLIENT TRACKING ON REDIRECT 123 BCAST,则所有匹配 key 的修改都会向 client 123 发送invalidate消息
注意:INCRBYFLOAT、HINCRBY 这类命令也会触发失效,但 GETRANGE、STRLEN 不会注册 key 到 tracking 表 —— 它们不算“读取整个 key 的语义”。
为什么你的 client 收不到 invalidate 消息
最常被忽略的点是:tracking 消息走的是 RESP 协议的 **push message**,不是 PUB/SUB,也不是普通 reply。客户端必须提前声明支持,并持续读取非请求响应流。
- Python redis-py 默认不处理 push message,需用
redis.Redis(connection_class=redis.Connection)并手动调用parse_response()循环检测 - Java Lettuce 需启用
ClientOptions.builder().publishOnScheduler(true)并监听CommandHandler的 push 事件 - Node.js ioredis 要监听
invalidated事件,且必须在CLIENT TRACKING ON后立即执行一次读操作(如GET dummy)来激活连接状态 - 如果 client 在收到
invalidate前断开,Redis 不重发;也没有 ACK 机制 —— 这意味着网络抖动或消费延迟会导致本地缓存脏读
tracking 的本质是尽力而为的轻量通知,不是强一致消息队列。真要保序保达,得在外围加一层 Kafka 或 Redis Stream 做中转。










