搞懂Redis (六) - 发布与订阅

高手们,请教一下,搞懂Redis (六) - 发布与订阅
最新回答
陌上画桑

2024-09-21 01:57:03

Redis发布与订阅是一种消息通信的模式:发布者(pub)发送消息,订阅者(sub)接收消息。

Redis通过publish和subscribe等命令实现了订阅与发布模式,这个功能提供两种消息机制,分别是订阅/发布到频道、订阅/发布到模式的客户端

1 频道(channel)

订阅

发布 完整流程

发布者发布消息

发布者向频道channel:1发布消息 hi

127.0.0.1:6379>?publish?channel:1?hi(integer)?1

订阅者订阅消息

127.0.0.1:6379>?subscribe?channel:1Reading?messages...?(press?Ctrl-C?to?quit)1)?"subscribe"?//?消息类型2)?"channel:1"?//?频道3)?"hi"?//?消息内容

执行subscribe后客户端会进入订阅状态,仅可以使subscribe、unsubscribe、psubscribe和punsubscribe这四个属于“发布\订阅”之外的命令

订阅频道后的客户端可能会收到三种消息类型

subscribe 表示订阅成功的反馈信息。第二个值是订阅成功的频道名称,第三个是当前客户端订阅的频道数量

message 表示接受到的消息,第二个值表示产生消息的频道名称,第三个值是消息的内容

unsubscribe 表示成功取消订阅某个频道,第二个值是对应的频道名称,第三个值是当前客户端订阅的频道数量,当此值为0时,客户端会退出订阅状态,之后就可以执行其他非“发布\订阅”模式的命令了。

数据结构

基于频道的发布订阅模式是通过字典数据类型实现的

struct?redisServer?{????//?...????dict?*pubsub_channels;????//?...};

其中,字典的键为正在被订阅的频道,而字典的值则是一个链表,链表中保存了所有订阅这个频道的客户端 订阅

当使用subscribe订阅时,在字典中找到频道key(如没有则创建),并将订阅的client关联在链表后面。 当client 10执行subscribe channel1,channel2,channel3时,会将client10分别加到channel1,channel2,channel3关联的链表尾部

发布

发布时,根据key,找到字典汇总key的地址,然后将msg发送到关联的链表每一台机器

退订

遍历关联的链表,将指定的地址删除即可

2 模式(pattern)

pattern使用了通配符的方式来订阅

通配符中?表示1个占位符,表示任意个占位符(包括0),?\ 表示1个以上占位符 所以当使用publish命令发送信息到某个频道时,不仅所有订阅该频道的客户端会收到信息,如果有某个\某些模式和这个频道匹配的话,那么所有订阅这个\这些频道的客户端也同样会收到信息

订阅发布完整流程

发布者发布消息

127.0.0.1:6379>?publish?b?m1(integer)?1127.0.0.1:6379>?publish?b1?m1(integer)?1127.0.0.1:6379>?publish?b11?m1(integer)?1

订阅者订阅消息

127.0.0.1:6379>?psubscribe?b*Reading?messages...?(press?Ctrl-C?to?quit)1)?"psubscribe"2)?"b*"3)?(integer)?31)?"pmessage"2)?"b*"3)?"b"4)?"m1"1)?"pmessage"2)?"b*"3)?"b1"4)?"m1"1)?"pmessage"2)?"b*"3)?"b11"4)?"m1"

数据结构

pattern属性是一个链表,链表中保存着所有和模式相关的信息

struct?redisServer?{????//?...????list?*pubsub_patterns;????//?...};//?链表中的每一个节点结构如下,保存着客户端与模式信息typedef?struct?pubsubPattern?{????redisClient?*client;????robj?*pattern;}?pubsubPattern;

数据结构如下:

订阅

当有新的订阅时,会将订阅的客户端和模式信息添加到链表后面

发布

当发布者发布消息时,首先会发送到对应的频道上,在遍历模式列表,根据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)

退订

使用punsubscribe,可以将订阅者退订,将改客户端移除出链表。

原文:https://juejin.cn/post/7095632413312679943