Golang Redis Pub/Sub:Close与Unsubscribe退订频道推荐方案
Golang 操作Redis Pub/Sub 退订相关问题解答
参考示例代码如下:
pubsub := rdb.Subscribe(ctx, "mychannel1") // 方式1:结束时关闭订阅实例 defer pubsub.Close() // 方式2:退订指定频道 defer pubsub.Unsubscribe(ctx, "mychannel1") ch := pubsub.Channel() for msg := range ch { fmt.Println(msg.Channel, msg.Payload) }
推荐的退订方式
不再需要使用订阅时,优先选择pubsub.Close()做最终的资源释放,原因如下:
- 从go-redis的底层实现来看,
Close()是完整的资源清理操作:会自动给Redis发送所有已订阅频道的退订指令、关闭内部消息通道、释放持有的网络连接和后台协程资源,不会留下泄漏点。而单独调用Unsubscribe(ctx, "mychannel1")仅会退订传入的这一个频道,pubsub实例本身持有的连接、协程、通道资源都不会被释放,长期运行会导致内存、连接泄漏。 - 两种方法的适用场景完全不同:
Unsubscribe仅适合订阅运行期间动态取消部分频道订阅、但还要保留订阅实例接收其他频道消息的场景。比如你同时订阅了频道A、B、C,中途不需要再收A的消息,这时候调用Unsubscribe退订A即可,不需要销毁整个订阅实例。 - 如果你通过
pubsub.Channel()拿到了原生Go channel做for range遍历,Close()执行时会主动关闭这个消息channel,能让遍历循环正常退出,不会造成读协程永久阻塞。如果只调用单个频道的Unsubscribe,只要实例还订阅着其他频道,遍历循环就会一直阻塞等待消息;哪怕退订了所有频道,没有执行Close的话,内部残留的协程和连接也不会被回收。
是否需要手动删除Pub/Sub频道
不需要手动删除。
Redis的Pub/Sub频道没有持久化的实体结构,本质是服务端做消息转发的临时匹配规则,不会占用持久化存储空间。当某个频道没有任何活跃订阅者时,Redis会自动回收该频道相关的临时资源,服务端本身也没有提供“手动删除频道”的操作接口,用户不需要做任何额外处理。
内容的提问来源于stack exchange,提问作者Prata
相关产品推荐
相关产品推荐

