目录
编辑
一、发布与订阅
6.1 频道
6.1.1 发布
6.1.2 订阅
6.1.3 数据结构
6.1.3.1 订阅(channel)
6.1.3.2 发布
6.1.3.3 退订
6.2 模式(pattern)
6.2.1 发布
6.2.2 订阅
6.2.3 数据结构
6.2.3.1 发布
6.2.3.2 订阅
6.2.3.3 退订
6.3 使用场景
6.3.1 哨兵间通信
6.3.2 消息队列
一、发布与订阅
redis发布与订阅是一种消息通信的模式:发送者(pub)发送消息,订阅者(sub)接收消息。
redis通过PUBLISH和SUBSCRIBE等命令实现了订阅与发布模式,这个功能提供两种信息机制,分别是订阅/发布到频道、订阅/发布到模式的客户端。
6.1 频道
6.1.1 发布
发布者发布消息
发布者向频道channel:1发布消息hi
127.0.0.1:6379> publish channel:1 hi
(integer) 1
6.1.2 订阅
订阅者订阅消息
127.0.0.1:6379> subscribe channel:1
Reading messages... (press Ctrl-C to quit)
1) "subscribe" // 消息类型
2) "channel:1" // 频道
3) "hi" // 消息内容
执行subscribe后客户端会进入订阅状态,仅可以使subscribe、unsubscribe、psubscribe和punsubscribe这四个属于"发布/订阅"之外的命令
订阅频道后的客户端可能会收到三种消息类型
- subscribe。表示订阅成功的反馈信息。第二个值是订阅成功的频道名称,第三个是当前客户端订阅的频道数量。
- message。表示接收到的消息,第二个值表示产生消息的频道名称,第三个值是消息的内容。
- unsubscribe。表示成功取消订阅某个频道。第二个值是对应的频道名称,第三个值是当前客户端订阅的频道数量,当此值为0时客户端会退出订阅状态,之后就可以执行其他非"发布/订阅"模式的命令了。
6.1.3 数据结构
基于频道的发布订阅模式是通过字典数据类型实现的
struct redisServer {
// ...
dict *pubsub_channels;
// ...
};
其中,字典的键为正在被订阅的频道, 而字典的值则是一个链表, 链表中保存了所有订阅这个频道的客户端。
6.1.3.1 订阅(channel)
当使用subscribe订阅时,在字典中找到频道key(如没有则创建),并将订阅的client关联在链表后面。
当client 10执行subscribe channel1 channel2 channel3时,会将client 10分别加到 channel1 channel2 channel3关联的链表尾部。
6.1.3.2 发布
发布时,根据key,找到字典汇总key的地址,然后将msg发送到关联的链表每一台机器。
6.1.3.3 退订
遍历关联的链表,将指定的地址删除即可。
6.2 模式(pattern)
pattern使用了通配符的方式来订阅
通配符中?表示1个占位符,*表示任意个占位符(包括0),?*表示1个以上占位符。
所以当使用 publish命令发送信息到某个频道时, 不仅所有订阅该频道的客户端会收到信息, 如果有某个/某些模式和这个频道匹配的话, 那么所有订阅这个/这些频道的客户端也同样会收到信息。
6.2.1 发布
发布者发布消息
127.0.0.1:6379> publish b m1
(integer) 1
127.0.0.1:6379> publish b1 m1
(integer) 1
127.0.0.1:6379> publish b11 m1
(integer) 1
6.2.2 订阅
订阅者订阅消息
127.0.0.1:6379> psubscribe b*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "b*"
3) (integer) 3
1) "pmessage"
2) "b*"
3) "b"
4) "m1"
1) "pmessage"
2) "b*"
3) "b1"
4) "m1"
1) "pmessage"
2) "b*"
3) "b11"
4) "m1"
6.2.3 数据结构
pattern属性是一个链表,链表中保存着所有和模式相关的信息。
struct redisServer {
// ...
list *pubsub_patterns;
// ...
};
// 链表中的每一个节点结构如下,保存着客户端与模式信息
typedef struct pubsubPattern {
redisClient *client;
robj *pattern;
} pubsubPattern;
6.2.3.1 发布
当发布者发布消息时,首先会发送到对应的频道上,在遍历模式列表,根据key匹配模式,匹配成功将消息发给对应的订阅者。
完成的发布伪代码如下:
def PUBLISH(channel, message):
# 遍历所有订阅频道 channel 的客户端
for client in server.pubsub_channels[channel]:
# 将信息发送给它们
send_message(client, message)
# 取出所有模式,以及订阅模式的客户端
for pattern, client in server.pubsub_patterns:
# 如果 channel 和模式匹配
if match(channel, pattern):
# 那么也将信息发给订阅这个模式的客户端
send_message(client, message)
6.2.3.2 订阅
当有信的订阅时,会将订阅的客户端和模式信息添加到链表后面。
6.2.3.3 退订
使用punsubscribe,可以将订阅者退订,将改客户端移除出链表。
6.3 使用场景
6.3.1 哨兵间通信
哨兵集群中,每个哨兵节点利用 Pub/Sub 发布订阅实现哨兵之间的相互发现彼此和找到 Slave。
哨兵与 Master 建立通信后,利用 master 提供发布/订阅机制在 `__sentinel__:hello`发布自己的信息,同时订阅这个频道来获取其他哨兵的信息,就这样实现哨兵间通信。
6.3.2 消息队列
我们也可以利用 Redis 发布订阅实现 轻量级简单的 MQ 功能 ,实现上下游解耦,需要注意点是 Redis 发布订阅的消息不会被持久化,所以新订阅的客户端将收不到历史消息。
也不支持 ACK 机制,所以当前业务不能容忍这些缺点,那就使用专业的消息队列,如果能容忍那就能享受 Redis 快带来的优势。
好了,今天关于Redis发布/订阅的内容就分享到这里,如果觉得对您有帮助,欢迎点赞+收藏+关注!