核心不是“能不能做”,而是“要不要自己造轮子”:redis.PubSub适合低延迟、不保证送达的广播通知(如配置刷新),而需可靠投递时应改用Redis Streams。

Go 语言开发 Redis 通知微服务,核心不是“能不能做”,而是“要不要自己造轮子”——redis.PubSub 能直接支撑轻量级通知,但若需消息确认、重试、多消费者负载均衡或持久化回溯,就得补协议层(比如用 BLPOP + list 做队列,或引入 redis-streams)。
用 redis.PubSub 实现即时广播通知
适合内部服务间低延迟、不保证送达的事件广播(如配置刷新、缓存失效信号)。Go 官方 github.com/go-redis/redis/v9 的 Subscribe 方法开箱即用,但要注意它默认不重连,且订阅连接不能复用命令连接。
- 必须单独建一个
*redis.Client专用于Subscribe,否则调用Subscribe后该连接会进入 pub/sub 模式,不能再发GET、SET等命令 -
redis.PubSub的ReceiveTimeout控制阻塞等待时长,设太短会频繁轮询,设太长则通知延迟高;建议 3–5 秒 - 收到
*redis.Message后,Message.Payload是原始字节,需自行json.Unmarshal,别漏掉错误检查
用 redis.Streams 实现可靠通知队列
需要至少一次投递(at-least-once)、消费者组、消息未确认自动重入队时,XADD/XREADGROUP 是更稳的选择。Redis 5.0+ 原生支持,Go 客户端通过 XAdd 和 XReadGroup 调用。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 发送端用
XAdd,StreamName建议带业务前缀(如notify:order),避免不同服务混用同一流 - 消费者组名(
group)必须提前用XGROUP CREATE创建,否则XReadGroup报错NOGROUP No such key or consumer group - 每个消费者需指定唯一
consumerName,否则同名 consumer 的未确认消息会被覆盖;可用主机名+pid 生成 -
XReadGroup的Count参数控制单次拉取条数,设为 10–50 较平衡吞吐与内存占用
避免常见坑:连接泄漏与消息积压
通知服务长期运行,连接和消息状态管理稍有疏忽就会雪崩。最常踩的两个点是连接未关闭、stream 消息未 XAck。
立即学习“go语言免费学习笔记(深入)”;
- 使用
defer conn.Close()不适用于 pub/sub 连接——它不会真正断开,只是归还到连接池;应显式调用pubsub.Close() - 用 streams 时,处理完一条消息后必须立即
XAck,否则该消息永远卡在PENDING状态,XPending查到大量 pending 条目就是这个原因 - 消费者重启后,若没正确从
last_id恢复读取位置,可能重复消费或跳过消息;建议将last_id存本地文件或 etcd,而非仅靠内存
真正难的不是写通第一条通知,而是让服务在 Redis 故障、网络抖动、消费者崩溃时还能收敛状态——redis.Streams 提供了基础能力,但 ACK 时机、重试策略、死信归档,这些得自己闭环,没法靠 client 库自动兜底。

















