Jedis subscribe() 会阻塞线程,必须在独立线程中调用;onMessage() 是唯一消息处理入口;连接断开需手动重试;RedisMessageListenerContainer 需设 phase 为 Integer.MIN_VALUE 以早初始化;Python redis-py 要判 type 再取 data 并解码;频道名推荐小写点分隔,禁用通配符滥用;订阅端须加健康检查与自动恢复。

Java 用 Jedis 订阅频道,subscribe() 会阻塞线程
直接调用 jedis.subscribe(pubsub, "myChannel") 后,当前线程就卡住了——它不会返回,也不会继续往下执行。这不是 bug,是 Redis Pub/Sub 的设计使然:订阅者必须长期保持连接并等待消息。
- 必须在独立线程中调用
subscribe(),否则主线程或 Web 请求线程会被锁死 -
JedisPubSub子类里的onMessage()是唯一处理入口,别指望它自动触发 Spring Bean 或事务上下文 - 如果 Redis 连接断开(比如服务重启),
subscribe()会抛异常并退出,不会自动重连——得自己包一层循环重试逻辑
Spring Data Redis 里 RedisMessageListenerContainer 怎么配才不漏消息
它本身不“漏”,但默认配置下容易让你误以为漏了:容器启动后才开始监听,而 Pub/Sub 是无缓冲的——发布时没人在线,消息就彻底丢弃。
- 确保
RedisMessageListenerContainer的setPhase()设为Integer.MIN_VALUE,让它比其他 Bean 更早初始化 - 不要依赖
@PostConstruct发布测试消息,因为监听器可能还没真正 ready;改用ApplicationRunner并加短延时 - 若需模式匹配(如
logs.*),必须用PSUBSCRIBE,对应配置要用PatternTopic,不是ChannelTopic
Python 用 redis-py 监听时,pubsub.listen() 返回的 message 字段要小心
每次迭代拿到的 message 是个字典,但类型不止 "message" 一种——还有 "subscribe"、"unsubscribe"、"psubscribe" 等控制流消息,直接取 message["data"] 会报 KeyError。
- 务必先判断
message["type"] == "message"再读message["data"] -
message["data"]是 bytes 类型,Python 3 下需显式解码:message["data"].decode("utf-8") - 别在
for message in pubsub.listen():里做耗时操作(如写 DB、发 HTTP),否则会积压,甚至被 Redis 断连——建议丢进线程池或队列异步处理
Redis 频道名本身不需要“创建”,但命名不当会引发冲突
Redis 不像 Kafka 那样需要预建 topic,频道是随第一次 PUBLISH 或 SUBSCRIBE 动态生成的。但名字没规范,后期维护就头疼。
- 避免纯数字或空格名(虽语法允许),如
"123"或"user update",容易和命令混淆或解析失败 - 推荐用小写+点号分隔层级:
"order.created"、"notification.sms",方便 PSUBSCRIBE 分组监听 - 生产环境慎用通配符模式(如
"*"),一个错配可能让监听进程扛不住广播风暴









