一、基础概念
- 频道(Channel):消息的“主题”或“标签”,生产者发布到频道,消费者订阅感兴趣的频道。
- 发布者(Publisher):使用
PUBLISH
命令发送消息,不关心有无订阅者。 - 订阅者(Subscriber):使用
SUBSCRIBE
/PSUBSCRIBE
命令接收对应频道或模式消息。 - 解订阅(Unsubscribe):使用
UNSUBSCRIBE
/PUNSUBSCRIBE
停止接收特定频道或模式的消息。
投递语义:Redis Pub/Sub 属于**最多一次(at-most-once)**投递,消息不落地,不重试;若需更强可靠性,请考虑 Redis Streams。
二、核心命令详解
# 订阅任意数量的频道
SUBSCRIBE <channel> [<channel> ...]
# 取消订阅指定频道;不带参数则取消所有
UNSUBSCRIBE [<channel> ...]
# 发布消息到频道,返回当前订阅者数量
PUBLISH <channel> <message>
RESP2 协议下,订阅状态的客户端仅能执行少量命令(PING
、QUIT
、SUBSCRIBE/UNSUBSCRIBE
、PSUBSCRIBE/PUNSUBSCRIBE
);RESP3 则无此限制,可随时执行任意命令。
三、消息格式与协议示例
Redis 会将订阅确认与消息以数组格式推送给客户端,三要素分别为:
- 类型:
subscribe
、unsubscribe
、message
- 频道或模式
- 数据:订阅计数(前两种类型)或消息内容(
message
)
Wire Protocol 示例(RESP2):
*3
$9
subscribe
$5
first
:1
*3
$7
message
$5
first
$5
Hello
四、模式匹配订阅
# 订阅所有以 news. 开头的频道
PSUBSCRIBE news.*
# 取消模式订阅
PUNSUBSCRIBE news.*
- pmessage:收到的模式匹配消息
- 格式:
pmessage | 原始模式 | 具体频道 | 消息内容
- 同时精确与模式订阅时,同条消息可收到多次。
五、投递语义对比
特性 | Pub/Sub | Streams |
---|---|---|
消息存储 | 不持久化 | 持久化,可回溯 |
投递语义 | 最多一次(at-most-once) | 最多一次 / 至少一次 / 精确一次 |
消费组支持 | 无 | 支持消费组,消费者各自进度独立 |
使用场景 | 实时通知、在线聊天 | 日志聚合、任务队列、审计 |
六、集群与分片 Pub/Sub
Redis 7.0 起支持分片 Pub/Sub,通过以下命令限定在特定槽(slot)内部传播,降低总线压力:
SSUBSCRIBE <shard_channel>
SPUBLISH <shard_channel> <message>
SUNSUBSCRIBE <shard_channel>
优势:消息仅在所属分片间传播,便于大规模频道管理与隔离。
七、Go 语言编程示例
package main
import (
"context"
"fmt"
"time"
"github.com/go-redis/redis/v8"
)
func main() {
ctx := context.Background()
client := redis.NewClient(&redis.Options{Addr: "localhost:6379"})
// 订阅协程
go func() {
pubsub := client.Subscribe(ctx, "demo-channel")
defer pubsub.Close()
for msg := range pubsub.Channel() {
fmt.Printf("Received on %s: %s\n", msg.Channel, msg.Payload)
}
}()
// 发布循环
for i := 0; i < 5; i++ {
text := fmt.Sprintf("Message %d", i)
n, err := client.Publish(ctx, "demo-channel", text).Result()
if err != nil {
fmt.Println("Publish error:", err)
} else {
fmt.Printf("Published to %d subscribers: %s\n", n, text)
}
time.Sleep(time.Second)
}
time.Sleep(2 * time.Second)
}
要点:使用异步订阅,独立协程/线程读取消息;遇断线需自动重连并恢复订阅。
八、典型应用场景
- 在线聊天/即时通知:低延迟广播消息至在线用户
- 动态配置下发:配置中心变更时通知各服务刷新缓存
- 实时监控告警:将监控事件推送至告警系统或可视化面板
- 微服务事件总线:轻量级事件分发,解耦各业务模块
九、性能优化与注意事项
- 连接管理:订阅模式会阻塞连接,需留足连接数并监控状态。
- 频道命名规范:统一前缀(环境/服务名),避免冲突;如
prod:orders:created
。 - 消息体积控制:避免发送超大负载,必要时拆分或使用 Streams。
- 故障恢复:订阅客户端应监测异常并重连后重订阅;可结合心跳检测。
- 安全隔离:ACL 或独立实例,防止跨环境订阅互相干扰。
十、总结
Redis Pub/Sub 提供零配置、低成本的实时消息分发能力,适合对可靠性要求不高但追求低延迟的场景。当业务需求升级至严格的投递语义或持久化需求时,可平滑迁移到 Redis Streams。希望本文的系统化讲解与实战示例,能助你快速掌握 Redis Pub/Sub,并在生产环境中高效落地。