Redis 6.0 的发布订阅模式易致连接数暴涨,因每个 SUBSCRIBE 独占 TCP 连接且不可复用;推荐改用 CLIENT TRACKING BCAST PREFIX 模式,复用普通连接、依赖 RESP3 协议,并配合键空间通知(notify-keyspace-events "Kg")实现轻量缓存失效广播。

Redis 6.0 的发布订阅模式本身不优化客户端连接,反而容易因连接管理不当导致连接数暴涨或消息丢失;真正能缓解这个问题的,是结合 CLIENT TRACKING + PREFIX 广播模式 + 合理的连接生命周期控制。
为什么 SUBSCRIBE 会撑爆连接数?
每个执行 SUBSCRIBE 的客户端都会独占一个 TCP 连接,并且进入阻塞状态——它不能复用连接发其他命令,也不能被自动回收。当业务中有成百上千个前端或微服务实例各自 SUBSCRIBE __redis__:invalidate 时,Redis 实例的 client_count 会快速逼近 maxclients 上限,触发拒绝新连接或 OOM。
常见错误现象包括:
-
ERR max number of clients reached错误频发 -
redis-cli --latency显示延迟突增,但INFO clients中connected_clients持续高位 - 客户端收不到消息,但
PUBSUB NUMSUB __redis__:invalidate返回非零值——说明连接还挂着,但早已断开未清理
用 CLIENT TRACKING BCAST PREFIX 替代 SUBSCRIBE
这是 Redis 6.0 针对客户端缓存场景专门设计的轻量级替代方案,不依赖独立订阅连接,所有操作走普通请求连接。
实操建议:
- 服务端启用键空间通知:
notify-keyspace-events "Kg"(必须包含K和g) - 客户端在常规连接上执行:
CLIENT TRACKING ON BCAST PREFIX user:—— 表示只关心以user:开头的 key 变更 - 无需额外建立
SUBSCRIBE连接,也不用维护单独的监听线程 - 失效通知通过 RESP3 推送帧直接返回到当前连接,复用已有连接通道
注意:该模式仅支持 RESP3 协议客户端(如 redis-py >= 4.0.0、lettuce >= 6.1.0)。若用旧版客户端,必须走重定向模式(REDIRECT),但会引入额外连接和转发开销。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
重定向模式下如何避免连接泄漏?
当必须兼容 RESP2 客户端时,CLIENT TRACKING ON BCAST REDIRECT <client-id> 是唯一选择,但它把推送压力转移到了被重定向的客户端连接上——这个连接一旦断开,服务端不会自动清理重定向目标,导致无效转发堆积。
关键控制点:
- 调用
CLIENT ID获取当前连接 ID,再传给REDIRECT,不要硬编码或复用历史 ID - 被重定向的客户端连接必须保持活跃(例如定期发
PING),否则 Redis 不会主动关闭它 - 务必配合
CLIENT SETNAME命名连接,并在应用层记录映射关系,便于故障时用CLIENT LIST快速定位“僵尸重定向连接” - 禁用
tcp-keepalive 0,确保内核能及时发现断连并通知 Redis 清理
Pub/Sub 连接要不要用连接池?
不要。Redis 的 SUBSCRIBE 连接本质是单向长连接,无法像普通命令连接那样复用或归还——连接池里的空闲 SUBSCRIBE 连接会持续占用资源,且无法安全并发读取多频道消息。
可行做法只有两种:
- 每个业务逻辑单元(如一个用户会话、一个微服务实例)只维持**至多一个**专用
SUBSCRIBE连接,集中处理所有频道消息 - 改用
PSUBSCRIBE+ 通配符合并多个关注点(例如PSUBSCRIBE order:* user:*),减少连接数量
真正容易被忽略的是:Redis 默认不持久化 Pub/Sub 状态,服务重启后所有订阅关系丢失,客户端必须自行实现重连+重订阅逻辑,否则消息会静默中断。这点比连接数问题更隐蔽,也更致命。

















