跳转到主内容
极星编程网:以代码为星,赴技术山海!

Golang怎么Redis发布订阅_Golang如何用Publish和Subscribe收发消息【实战】

订阅需确认subscribe消息才生效,ReceiveMessage须分类处理错误,Publish返回值为在线订阅数而非成功标志,多频道应分实例避免故障扩散,PubSub非长连接需手动重建且须早于发布端启动。 Subscribe后收不到消息?先确认订阅是否真正生效 调用
rdb.Subscribe(ctx, "topic")
不等于“已经连上并开始收消息”,Redis 不会立刻返回确认,而是通过后续收到的
redis.Subscription
类型消息来反馈状态。很多人卡在这一步,频道名拼错(比如多空格、大小写不一致)、Redis ACL 拒绝
SUBSCRIBE
权限、或网络未就绪,都会导致静默失败——
ReceiveMessage()
一直阻塞,也不报错。 必须监听
pubsub.Channel()
,对每条消息做类型断言:
if sub, ok := msg.(*redis.Subscription); ok && sub.Kind == "subscribe" && sub.Count >= 1
,才算真正加入成功 首次订阅后,至少等 1–2 条
subscribe
消息后再处理业务消息,否则第一条业务消息可能被跳过 生产环境建议加心跳:定期调用
pubsub.Ping(ctx)
,若返回 error,说明连接已断,需重建
PubSub
实例 ReceiveMessage() 卡住或 panic?别只看 err != nil 就 break
ReceiveMessage()
是阻塞读,底层依赖 Redis 的 SUBSCRIBE 响应流。它可能返回三类典型值:真正的业务消息(
redis.Message
)、心跳超时(
redis.Nil
)、或上下文取消/网络错误(
context.Canceled
、
redis.ConnectionClosed
等)。只检查
err != nil
就退出循环,会导致 goroutine 提前终止、后续消息全丢。 正确做法是分类处理:
errors.Is(err, context.Canceled)
表示主动退出;
errors.Is(err, redis.Nil)
可忽略(Redis 心跳超时,正常);其他 err 才该打日志并考虑重试或重建连接 别在 for 循环里加
time.Sleep(100 * time.Millisecond)
等待——这会放大延迟且无法响应 cancel;应该用带 timeout 的 ctx 控制整体生命周期,例如
ctx, cancel := context.WithTimeout(parentCtx, 30*time.Second)
收到
redis.Message
后,务必检查
msg.Payload
长度是否为 0,Redis 允许发空字符串,但业务逻辑通常不期望它 Publish 返回 0 就是失败?不是,它只告诉你“此刻在线几人”
rdb.Publish(ctx, "topic", data)
的返回值
ret.Val()
是**当前在线且已成功订阅该频道的客户端数量**,不是“发送成功与否”的布尔值。返回 0 仅表示此刻没有活跃订阅者,不等于网络失败或权限错误;而
ret.Err()
才反映真实问题(如密码错误、ACL 拒绝
PUBLISH
权限)。 如果
ret.Val() == 0
,属于正常场景(比如订阅端还没启、刚断连、或频道名不一致),无需告警,更不该重试 只有
ret.Err() != nil
才需要处理:记录日志、重试(带指数退避)、或触发告警 发布端不能假设“发出去就有人收”——原生 Pub/Sub 不保存历史消息,断连期间发布的消息彻底丢失;若需可靠性,得换
Redis Stream
或加消息队列兜底 一个 PubSub 实例能订多个频道,但别混用、别复用
rdb.Subscribe(ctx, "order.created", "user.updated")
确实可行,所有消息都走同一个
ReceiveMessage()
流,靠
msg.Channel
区分来源。但这种“一实例多频道”模式极易引发连锁故障:某个频道异常(如消息格式错、回调 panic)、缓冲区溢出、或网络抖动,会拖垮所有频道的消息消费。 go语言参考手册 中文CHM版 Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。本文给大家带来Go参考手册,需要的可以来下载! Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。 Go 语言特色 简洁、快速、安全 并行、有趣、开源 内存管理、v数组安全、编译 下载 立即学习 “ go语言免费学习笔记(深入) ”; 生产环境建议:每个关键频道单独建
PubSub
实例,避免相互影响;不同实例用不同
context.Context
独立控制生命周期
PubSub
是短命对象,不是全局单例——它内部缓冲区默认仅 10 条,消费不及时就丢消息,且断连后不会自动重连+恢复订阅,必须手动重建 别把
redis.UniversalClient
和
redis.PubSub
当作同一类对象管理;前者可复用,后者每次重连都得
client.Subscribe()
新建 最常被忽略的点是:订阅端启动必须早于发布端,否则第一条消息永远收不到;还有就是
defer pubsub.Close()
必须写,否则连接泄漏,Redis 的
client list
里 idle 连接越堆越多,最终拖垮服务。

相关文章