Redis的发布订阅(Pub/Sub)功能提供了一种消息队列的实现方式,可以让发送方(发布者)向一个频道发布消息,订阅方(订阅者)则可以订阅相关频道接收消息。
1.发布订阅基本概念
发布订阅模式通过频道(channel)来实现消息的分发。发布者(publisher)可以向频道发布消息,订阅者(subscriber)可以订阅频道来接收消息。这种模式可以实现消息的异步传输。
在Redis中,客户端可以订阅任意数量的频道。当向被订阅的频道发布消息时,所有订阅该频道的客户端都会收到这条消息。
2.相关命令
SUBSCRIBE命令 – 订阅频道
SUBSCRIBE 命令用来订阅给定的一个或多个频道。语法如下:
SUBSCRIBE channel [channel ...]
例如:
SUBSCRIBE news.china news.world
这将订阅 news.china 和 news.world 两个频道。
UNSUBSCRIBE命令 – 取消订阅
UNSUBSCRIBE 命令用来取消对给定频道的订阅。语法如下:
UNSUBSCRIBE [channel [channel ...]]
例如:
UNSUBSCRIBE news.china
这将取消对 news.china 频道的订阅。
PSUBSCRIBE命令 – 使用模式订阅
PSUBSCRIBE 命令用于使用给定的模式订阅频道。语法如下:
PSUBSCRIBE pattern [pattern ...]
例如:
PSUBSCRIBE news.*
这将订阅所有以 news. 开头的频道。
PUNSUBSCRIBE命令 – 取消按模式的订阅
PUNSUBSCRIBE 命令用于取消给定模式的订阅。语法如下:
PUNSUBSCRIBE [pattern [pattern ...]]
PUBLISH命令 – 发布消息
PUBLISH 命令用于向给定的频道发布消息。语法如下:
PUBLISH channel message
例如:
PUBLISH news.china "新消息"
这将向 news.china 频道发布消息”新消息”。
go-redis 实现订阅发布
package main
import (
"fmt"
"time"
"github.com/go-redis/redis"
)
func subscriber(client *redis.Client) {
pubsub := client.Subscribe("mychannel")
// 使用模式订阅
// pubsub := client.PSubscribe(ctx, "mychannel*")
defer pubsub.Close()
// 处理订阅接收到的消息
for {
msg, err := pubsub.ReceiveMessage()
if err != nil {
return
}
fmt.Println(msg.Channel, msg.Payload)
}
}
func publisher(client *redis.Client) {
for {
// 发布消息到频道
err := client.Publish("mychannel", "hello").Err()
if err != nil {
panic(err)
}
time.Sleep(1 * time.Second)
}
}
func main() {
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
})
go subscriber(client)
go publisher(client)
<-make(chan struct{})
}
3. 使用场景
构建即时消息系统
可以通过发布订阅实现一个简单的聊天室。将每个聊天频道设为一个频道,用户发送消息就是向该频道发布消息,其他订阅了该频道的用户就可以收到消息。
异步任务处理
可以用来实现任务队列,通过发布消息将任务信息放到队列中,工作进程订阅频道获取任务并异步执行。
跨系统消息通知
例如订单系统完成下单后,可以发布一个消息到订单频道,物流系统订阅该频道获取订单信息来安排发货。
数据流处理
可以将实时产生的数据发布到频道中,数据处理程序订阅该频道获取流数据进行处理。比如接收实时的股票价格,进行处理后写入数据库。
4. 实现机制简介
普通模式
Redis发布订阅的实现机制主要涉及两个数据结构:
频道(channel)
频道是发布订阅的信息传递通道。每个频道都会维护一个订阅者链表,链表中存放了所有订阅这个频道的客户端。
订阅者(subscriber)
订阅者表示订阅了某些频道的客户端。每个客户端通过hash(dict)维护了订阅的所有频道。
当有新消息通过PUBLISH发布到某个频道时,Redis服务器会遍历这个频道对应的订阅者链表,将消息发布给每个订阅者客户端。
通过这个发布-订阅链表结构,Redis可以高效地实现频道订阅与消息发布分发的功能。这种机制使得频道与订阅者完全解耦,提高了Redis发布订阅功能的扩展性和性能。
pattern 模式
模式表(pubsub_patterns)
Redis用一个哈希表保存所有当前的订阅模式,哈希表的键就是模式,值是订阅这个模式的所有客户端列表。
客户端模式结构(client->pubsub_patterns)
客户端结构中也保存着这个客户端所有订阅的模式,用于快速判断一个消息的频道是否匹配了客户端的模式。
当一个频道发布新消息时,Redis会遍历模式表,检查是否有模式与这个频道匹配,如果匹配,就将消息发送给对应模式的客户端。
这样通过引入模式,可以实现更加灵活的订阅,如”news.*”可以订阅所有news相关的频道。
5. 最佳实践
使用注意事项
-
避免频道数量太多,可能导致内存占用过高
-
合理设置订阅的模式,避免匹配太广泛
-
设置消息过期时间,避免积压太多消息
-
不要依赖订阅者实时接收消息,发布订阅是异步的
常见问题及解决
-
消息积压:设置消息过期时间,并监控频道积压情况
-
消息丢失:确保订阅者及时读取消息,避免频道填满导致丢消息
-
客户端误订阅:每个订阅者指定订阅的频道,不使用无意义的通配符
-
消息重复:服务端去重,或由消费端幂等消费
-
订阅阻塞:确保消息能够正常消费,监控订阅者状态
此外,还要充分考虑发布订阅的异步性,不能简单地当作同步的远程调用使用。
原文始发于微信公众号(吃瓜技术派):Redis发布订阅功能详解
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/236061.html