Redis Pub/Sub不能直接推消息给WebSocket客户端,必须由应用层桥接;其仅在服务节点间中转消息,不存消息、不保序、不重试,浏览器无法直连Redis或执行SUBSCRIBE命令。

Redis Pub/Sub 本身不能直接推消息给 WebSocket 客户端,必须由应用层桥接。它只负责在多个 WebSocket 服务节点之间中转消息,不存消息、不保序、不重试——这点没搞清,后续所有设计都会跑偏。
为什么不能直接用 PUBLISH 把消息塞给浏览器
WebSocket 是客户端与服务端之间的长连接通道,而 Redis Pub/Sub 是服务端内部(或跨服务)的消息分发机制。浏览器根本连不上 Redis,也不理解 SUBSCRIBE 命令。常见错误是以为“前端订阅 Redis 频道”就能收消息,结果连握手都失败。
- Redis 不提供 WebSocket 协议支持,没有
ws://接口 -
SUBSCRIBE是阻塞命令,必须独占连接,不能复用 HTTP 连接或混在 WebSocket 帧里 - 前端 JS 无法直接调用 Redis 命令,必须经后端中转
- 真正链路是:
业务逻辑 → 后端发布到 Redis 频道 → 所有监听该频道的 WebSocket 服务节点收到 → 节点查本地 <code>WebSocketSession→ 推送到对应客户端
PSUBSCRIBE 和 SUBSCRIBE 在集群场景下怎么选
用 SUBSCRIBE 还是 PSUBSCRIBE,取决于你的路由粒度。如果每个用户有唯一频道(如 user:1001),用 SUBSCRIBE 更轻量;如果要按业务类型广播(如所有“订单状态变更”都走 order:status:* ),才用 PSUBSCRIBE。
-
SUBSCRIBE user:1001:精准投递,无匹配开销,适合点对点或单用户通知 -
PSUBSCRIBE order:status:*:模式匹配会消耗 CPU,Redis 6.2+ 才优化了 trie 匹配性能,老版本慎用 - 集群环境下,
PSUBSCRIBE的通配符不会跨分片生效——Redis Cluster 默认不支持模式订阅,必须用SHARDSUBSCRIBE(7.0+)或退回到单节点/Proxy 模式 - Spring Data Redis 的
MessageListenerContainer默认只支持SUBSCRIBE,要用PSUBSCRIBE得手动配置PatternTopic
消息丢失的三个高发时刻和应对方式
Redis Pub/Sub 是“即发即忘”,没消费者时消息直接丢。这不是 bug,是设计使然。容易丢消息的地方集中在连接生命周期边缘:
- WebSocket 服务节点启动时还没来得及
SUBSCRIBE,上游已PUBLISH—— 解决办法:启动完成后再初始化监听,加@PostConstruct或就绪探针校验 - 节点因 GC 或网络抖动短暂断开 Redis 订阅,期间消息全漏 —— 解决办法:用
RedisConnectionFactory配置reconnectOnException=true,并监听ConnectionFailedEvent主动重订 - 客户端断线重连后,服务端没同步会话状态,新连接被分配到另一台机器,旧频道没人监听 —— 解决办法:重连时带 userId,新节点先
PUBLISH一条session:handover:user:1001到全局频道,原节点清理本地 session 并转发积压消息(如有)
Spring Boot 中 RedisTemplate 和 ReactiveRedisTemplate 怎么选
别为了“响应式”强行上 ReactiveRedisTemplate。它和 MessageListenerContainer 不兼容,没法自动处理 Pub/Sub 订阅逻辑。除非你整套栈都是 WebFlux + R2DBC + reactive Redis,否则大概率会卡在“怎么让 Mono 订阅持续接收消息”这个坑里。
-
RedisTemplate+MessageListenerContainer:稳定、文档全、异常处理明确,适合绝大多数 Spring MVC 项目 -
ReactiveRedisTemplate:只能靠redisReactiveCommands.subscribe()手动管理连接生命周期,没有内置重连、无背压控制,onNext回调里做session.sendMessage()还得切回Schedulers.boundedElastic() - 真正需要 reactive 的地方是消息入站(比如 STOMP over WebSocket 的
SEND帧处理),不是 Pub/Sub 中转本身 - 如果你用的是
@EnableWebSocketMessageBroker+ STOMP,Pub/Sub 只用来同步 topic 订阅关系,那用哪个都影响不大
最常被忽略的一点:Redis Pub/Sub 的输出缓冲区默认只有 1MB,慢消费者(比如 WebSocket 节点处理消息太慢)会导致连接被强制断开,且不报错。上线前务必用 CONFIG GET client-output-buffer-limit 检查,并在监控里埋点 pubsubnumpat 和 pubsub numsub,否则消息静默丢失时连日志都抓不到源头。


















