得益于出色的设计和优秀的性能,Redis 支持很多功能。其中一个便是发布/订阅,让我们来看看如何使用这个功能吧!
发布/订阅模型
Redis 的 SUBSCRIBE
、UNSUBSCRIBE
和 PUBLISH
这三个命令实现了一个基于发布订阅的消息模型。在这个模型中,消息发送者(发布者)并不会把消息发送给特定的消息接受者(订阅者)。已发布的消息会被描述为通道,发布者事先并不知道有哪些订阅者,甚至它们是否存在。同样,订阅者也不知道发布者的存在,只是选中一个或多个感兴趣的通道,然后只接收它们感兴趣的消息。在这个模型中,我们实现了发布者和订阅者的解耦,因此它能够实现更好的扩展性和更加动态的网络拓扑。
举个例子,若要订阅 foo
和 bar
通道,客户端需要发送一个 SUBSCRIBE
命令,并提供通道名称作为参数:
SUBSCRIBE foo bar
之后,当其他客户端把消息发送至这两个通道,Redis 就会把它们推送至所有订阅者客户端。
客户端若已经订阅了一个或多个通道,则它不应该发送命令,即使它可以订阅或取消订阅其他通道。订阅和取消订阅的响应也是以消息的方式发送的,这样一来,客户端就可以不间断地读取消息流,其中的第一个元素代表了消息类型。对于已经订阅通道的客户端来说,允许的命令有:SUBSCRIBE
、SSUBSCRIBE
、SUNSUBSCRIBE
、PSUBSCRIBE
、UNSUBSCRIBE
、PUNSUBSCRIBE
、PING
、RESET
和 QUIT
。
请注意,在已订阅模式下,redis-cli
不会接受任何命令,并且只能通过 Ctrl-C
来退出它。
推送消息的格式
每一条消息都是一个包含三个元素的数组。
其中,第一个元素是消息类型,它有以下三种可能:
subscribe
:这代表我们成功订阅了某个通道,该通道由第二个参数给出,而第三个参数则代表了当前已订阅的通道总数。unsubscribe
:这代表我们成功取消订阅了某个通道,该通道由第二个参数给出。第三个参数则代表了当前已订阅的通道总数。如果最后一个参数是 0,这意味着当前没有订阅任何通道,那么客户端就可以发送任何 Redis 命令,因为当前不在发布/订阅状态。message
:这代表着当前消息真的是一条“消息”,是被其他客户端使用PUBLISH
命令发送的“消息”。第二个元素是通道的名称。第三个参数是实际的消息负载(大小)。
数据库与作用域
发布/订阅功能和 key 空间没有关系,它是故意被设置成这样的。同时,它和数据库成员也没有任何关系。
在 db 10 上发布消息,在 db 1 上也可以被订阅者接收到。
如果你需要某种类型的作用域,你可以把环境名作为通道名的前缀,比如 test、staging、production 等。
协议示例
SUBSCRIBE first second
*3
$9
subscribe
$5
first
:1
*3
$9
subscribe
$6
second
:2
此时,我们在另一个客户端上,使用 PUBLISH
命令,向名为 second
的通道发送一条消息:
PUBLISH second Hello
第一个客户端会收到:
*3
$7
message
$6
second
$5
Hello
我们再让客户端取消订阅所有通道,使用不带参数的 UNSUBSCRIBE
就可以做到:
UNSUBSCRIBE
*3
$11
unsubscribe
$6
second
:1
*3
$11
unsubscribe
$5
first
:0
模式匹配订阅
Redis 的发布/订阅实现支持通道名的模式匹配。客户端或许会想要使用 Unix 通配符风格,来订阅名称所有符合特定模式的通道。
比如说:
PSUBSCRIBE news.*
将会接受所有发往 news.art.figurative
、news.music.jazz
等通道的消息。所有 Unix 通配符风格的模式都是受支持的,因此多个通配符一起使用也行。
PUNSUBSCRIBE news.*
将会取消订阅所有名称符合该模式的通道。其他的订阅不会收到影响。
使用模式匹配订阅通道,而后接收到的消息的格式会有不同:
- 消息类型为
pmessage
:第二个参数是订阅的匹配模式,第三个参数是通道名称,最后一个参数是实际的消息负载(大小)。
PSUBSCRIBE
和 PUNSUBSCRIBE
命令与 SUBSCRIBE
和 UNSUBSCRIBE
命令相似,它们的消息格式的区别,也是体现在消息类型上,相应地变成了 pususcribe
和 punsubscribe
。
同时匹配多个模式的消息
如果客户端订阅了多个模式匹配,或是它既订阅了模式匹配,又直接订阅了通道。那么,它有可能会重复收到同一条消息。
比如:
SUBSCRIBE foo
PSUBSCRIBE F*
在上述例子中,如果一条消息放松到 foo
通道,客户端会接收到两条消息:一条类型为 message
,另一条类型为 pmessage
。
模式匹配中的订阅数
在 subscribe
、unsubscribe
、psubscribe
和 punsubscribe
等消息类型中,最后一个参数是仍然存活的订阅数。这个数字是客户端仍订阅着的通道或模式的总数。因此,只有到这个数字变为 0,代表已经取消了所有订阅时,客户端才会退出发布/订阅状态。
共享的发布/订阅
Redis 7.0.0 版本引入。
(省略)
后语
下一篇文章中,我将介绍 Redis 分布式锁:SETNX 实现。请保持关注喔!
参考
本文使用 CC BY-SA 4.0 国际协议 进行许可,欢迎 遵照协议规定 转载。
作者:六开箱
链接:https://lkxed.github.io/posts/redis-pub-sub/