Redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。Redis 客户端可以订阅任意数量的频道。
"发布/订阅"模式包含两种角色,分别是发布者和订阅者。发布者可以向指定的频道(channel)发送消息;订阅者可以订阅一个或者多个频道(channel),所有订阅此频道的订阅者都会收到此消息。
实例演示
演示了发布订阅是如何工作的。在我们实例中我们创建了订阅频道名为 redisChat
第一步:打开一个 redis 客户端,订阅频道 redisChat
redis> SUBSCRIBE redisChat Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "redisChat" 3) (integer) 1
第二步:另外再打开一个 redis 客户端,在频道 redisChat 上发布消息
redis> PUBLISH redisChat "Redis is a great caching technique" (integer) 1 redis> PUBLISH redisChat "Learn redis by w3cschool.cc" (integer) 1
第三步:查看第一次打开的 redis 客户端,会显示接受到的消息
1) "message" 2) "redisChat" 3) "Redis is a great caching technique" 1) "message" 2) "redisChat" 3) "Learn redis by w3cschool.cc"
发布订阅模式详解
Redis发布/订阅(Pub/Sub)是一种通信机制,将数据推到某个信息管道中,其他客户端可通过订阅这些管道来获取推送信息,以此用于消息的传输。
由三部分组成:发布者(Publisher)、频道(Channel)、订阅者(Subscriber)。
发布者发布的消息分到不同的频道,不需要知道什么样的订阅者者订阅。订阅者对一个或多个频道感兴趣,只需要接收感兴趣的消息,不需要知道什么样的发布者发布。主要目的是解除消息的发布者与订阅者之间的耦合关系。发布者和订阅者都是Redis客户端,频道则是服务器端。
原理
Redis通过
SUBSCRIBE
,
PSUBSCRIBE
,
UNSUBSCRIBE
和
PUNSUBSCRIBE
等命令实现发布和订阅功能。
在Redis底层结构中,客户端和频道的订阅关系是通过一个字典加链表的结构保存的,如下图:
在 Redis 的底层结构中,redis服务器中定义了一个 pubsub_channels 字典,用于保存所有频道的订阅关系,在这个字典中,key 为所有频道名称,value 结构是一个链表,其中存放的是所有订阅这个频道的订阅者客户端。subscribe 命令的实质即为在key中添加value的订阅链。若频道首次被订阅说明在字典中并不存在该渠道的信息,那么程序首先要新建一个对应的 key,并且要赋值一个空链表,然后将对应的客户端加入到链表中。此时链表只有一个元素。若该渠道已经被其他客户端订阅过:这个时候就直接找到key值对应的value客户端信息添加到链表的末尾即可。
推送的消息格式
所有订阅接收的消息均为由三个元素组成的多块响应。
第一个元素是消息类型,有三种类型:
-
subscribe
:该类型表示成功订阅到频道响应,此时第二个元素为订阅的频道名称,第三个元素为已订阅的频道数量,例:
redis> SUBSCRIBE myChannel Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "myChannel" 3) (integer) 1
-
unsubscribe
:该类型表示成功取消订阅到的频道响应,此时第二个元素为订阅的频道名称,第三个元素为已订阅的频道数量,例:
redis> UNSUBSCRIBE myChannel 1) "unsubscribe" 2) "myChannel" 3) (integer) 0
-
message
:该类型表示订阅者客户端接收到其他客户端发出的发布命令结果,此时第二个元素表示来源频道的名称,第三个元素是实际的消息内容,例:
redis> SUBSCRIBE myChannel myChannel2 1) "subscribe" 2) "myChannel" 3) (integer) 1 1) "subscribe" 2) "myChannel2" 3) (integer) 2 1) "message" 2) "myChannel1"
发布订阅命令
发送消息
PUBLISH
命令为发送信息,返回值为接收到该消息的订阅者数量。
redis> PUBLISH mychannel "Hello" (integer) 1 redis> PUBLISH mychannel "World" (integer) 1
订阅频道
SUBSCRIBE
命令为订阅频道,返回值消息格式如上所述。
redis> SUBSCRIBE myChannel Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "myChannel" 3) (integer) 1 1) "message" 2) "myChannel" 3) "Hello" 1) "message" 2) "myChannel"
模式匹配
PSUBSCRIBE
命令订阅一个或多个符合给定模式的频道。每个模式以
*
作为匹配符,例如 news.*匹配所有以 news.开头的频道(news.one、news.global.today 等等)。
redis> PSUBSCRIBE new.* 1) "psubscribe" 2) "new.*" 3) (integer) 1 1) "pmessage" 2) "new.*" # 消息匹配的模式 3) "new.one" # 消息本身的目标频道
注:当订阅客户端同时订阅某种模式和符合该模式的具体某个频道时,那么会接收到发布者推送的信息两次,两次接收的信息格式不同,一个为 message 类型,另一个为 pmessage 类型,消息内容一致。
取消订阅
UNSUBSCRIBE
命令为取消订阅频道,与订阅频道命令相同,也有对应匹配模式
PUNSUBSCRIBE
。
如果没有填写指定频道,即一个无参数的
UNSUBSCRIBE
被调用执行,那么该客户端订阅的所有频道都会被退订。
由于Redis的订阅操作是阻塞式的,因此一旦客户端订阅了某个频道或模式,就将会一直处于订阅状态直到退出。在
SUBSCRIBE
,
PSUBSCRIBE
,
UNSUBSCRIBE
和
PUNSUBSCRIBE
命令中,其返回值都包含了该客户端当前订阅的频道和模式的数量,当这个数量变为0时,该客户端会自动退出订阅状态。