go用go-redis做redis pub/sub必须先调pubsub.receive()确认subscribe生效,再处理业务消息;需分别处理redis.message、redis.nil和真实错误;publish返回值为订阅客户端数而非成功标志;多频道共用一通道须手动分流,且必须显式close防泄漏。

Go 用 go-redis 做 Redis Pub/Sub,不是“连上就能收”,而是极易因初始化顺序、错误分类缺失、连接生命周期管理不当,导致静默丢消息或 goroutine 泄漏。
订阅前必须确认 SUBSCRIBE 已生效,不能跳过 Receive()
调用 rdb.Subscribe(ctx, "topic") 只是发起订阅请求,Redis 不会立刻响应。如果直接进入 ReceiveMessage() 循环,可能永远卡住——尤其当频道名拼错(如 "order.created " 多了个空格)、ACL 拒绝 SUBSCRIBE 权限、或网络未就绪时,ReceiveMessage() 既不返回消息也不报错。
- 必须先调用一次
pubsub.Receive(ctx)等待*redis.Subscription类型消息,检查sub.Kind == "subscribe"且sub.Count >= 1,才算真正加入成功 - 首次收到
subscribe消息后,建议再等 1–2 条(或加time.Sleep(10ms)),避免第一条业务消息被跳过 - 别把
Receive()和ReceiveMessage()混用:前者用于握手确认,后者用于收业务消息;混用会导致类型断言失败或 panic
ReceiveMessage() 的三类返回值必须分别处理
ReceiveMessage() 是阻塞读,可能返回 redis.Message、redis.Nil(心跳超时)、或真实错误(如 context.Canceled、redis.ConnectionClosed)。只写 if err != nil { break } 会提前退出 goroutine,后续所有消息全丢。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
-
errors.Is(err, context.Canceled):主动取消,可安全退出 -
errors.Is(err, redis.Nil):Redis 心跳超时,忽略即可,继续循环 - 其他 error(如网络中断、认证失败):打日志,考虑重建
PubSub实例,而非直接 panic 或 return - 收到
redis.Message后,务必检查len(msg.Payload) == 0,Redis 允许发空字符串,但多数业务逻辑不应接受
发布端 Publish() 返回值不是 success/fail,而是在线订阅数
rdb.Publish(ctx, "topic", data).Val() 返回的是当前**已连接且完成 SUBSCRIBE 的客户端数量**,不是“发送是否成功”的布尔值。返回 0 很常见,不代表出错。
-
rdb.Publish(...).Err()才反映真实问题:比如 ACL 拒绝PUBLISH权限、密码错误、Redis 不可达 - 返回 0 的典型场景:订阅端还没启动、刚断连、频道名大小写不一致、或
Subscribe()调用后没走完Receive()握手流程 - 别在发布后 sleep 等待订阅者上线——这不可靠;应由订阅端保证早于发布端启动,或用重试 + backoff 机制应对临时无订阅者
多频道订阅与连接泄漏是最常被忽略的两个坑
一个 PubSub 实例可同时订阅多个频道:rdb.Subscribe(ctx, "a", "b", "c"),但所有消息都走同一个 ReceiveMessage() 流,需靠 msg.Channel 区分来源。而更隐蔽的问题是连接泄漏。
- 每个
PubSub实例对应一个独立 TCP 连接,必须显式调用defer pubsub.Close();漏掉这句,Redis 的client list里 idle 连接会持续堆积 - 不要复用主
*redis.Client去调用Subscribe(),它返回的是*redis.PubSub,不能执行GET/SET,也不能拿它去Publish() - 生产环境建议加心跳:
pubsub.Ping(ctx)定期探测连接状态,失败则重建实例;别依赖ReceiveMessage()自动恢复
Pub/Sub 在 Go 里不是开箱即用的“消息队列”,它没有持久化、不保证送达、连接脆弱。真正关键的不是怎么写第一行 Subscribe,而是怎么让 goroutine 在各种网络抖动、Redis 重启、上下文取消下,既不泄漏也不丢消息。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










