Redis提供了基于“发布/订阅”模式的消息机制,此种模式下,消息发布者和订阅者不进行直接通讯,发布者客户端向指定的频道(channel)发布消息,订阅该频道的每一个客户端均可以收到该消息(频道没有”建立“的概念,能够直接订阅、亦可直接发布消息)。python
自2.0.0可用。redis
时间复杂度:O(N+M),其中
N
是频道channel
的订阅者数量,而M
则是使用模式订阅(subscribed patterns)的客户端的数量。shell
将信息 message
发送到指定的频道 channel
。segmentfault
接收到信息 message
的订阅者数量。测试
# 向没有订阅者的频道发送信息 coderknock> PUBLISH new_channel "test publish" (integer) 0 # 向有订阅者的频道发送信息 coderknock> PUBLISH channel1 "new channel1" (integer) 1
自2.0.0可用。ui
时间复杂度:O(N),其中
N
是订阅的频道的数量。命令行
订阅给定的一个或多个频道的信息。code
接收到的信息(请参见下面的代码说明)。blog
coderknock> SUBSCRIBE channel1 Reading messages... (press Ctrl-C to quit) # 订阅成功 1) "subscribe" # 返回值的类型:显示订阅成功 2) "channel1" # 订阅的频道名字 3) (integer) 1 # 目前已订阅的频道数量 # 接收到信息 1) "message" # 返回值的类型:信息 2) "channel1" # 来源(从哪一个频道发送过来) 3) "new channel1" # 信息内容
#### PSUBSCRIBE队列
自2.0.0可用。
时间复杂度:O(N),
N
是订阅的模式的数量。
订阅一个或多个符合给定模式的频道。
每一个模式以 *
做为匹配符,好比 it*
匹配全部以 it
开头的频道( it.news
、 it.blog
、 it.tweets
等等), news.*
匹配全部以 news.
开头的频道( news.it
、 news.global.today
等等),诸如此类。
接收到的信息(请参见下面的代码说明)。
coderknock> PSUBSCRIBE news.* coderknock.* Reading messages... (press Ctrl-C to quit) # 订阅成功 1) "psubscribe" # 返回值的类型:显示订阅成功 2) "news.*" # 订阅的频道名字 3) (integer) 1 # 目前已订阅的频道数量 1) "psubscribe" 2) "coderknock.*" 3) (integer) 2 # 接收到信息 1) "pmessage" # 返回值的类型:信息 2) "news.*" # 来源频道模式 3) "news.123" # 具体频道(从哪一个频道发送过来) 4) "123 # 消息 1) "pmessage" 2) "news.*" 3) "news.222" 4) "222"
### 查看发布/订阅系统状态
### PUBSUB
自2.8.0可用。
时间复杂度:O(N),
N
是订阅的模式的数量。
PUBSUB
是一个查看订阅与发布系统状态的内省命令, 它由数个不一样格式的子命令组成, 如下将分别对这些子命令进行介绍。
列出当前的活跃频道。
活跃频道指的是那些至少有一个订阅者的频道, 订阅模式的客户端不计算在内。
pattern
参数是可选的:
若是不给出 pattern
参数,那么列出订阅与发布系统中的全部活跃频道。
若是给出 pattern
参数,那么只列出和给定模式 pattern
相匹配的那些活跃频道。
N
为活跃频道的数量(对于长度较短的频道和模式来讲,将进行模式匹配的复杂度视为常数)。# 客户端1 coderknock> SUBSCRIBE coderknock sanchan news test Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "coderknock" 3) (integer) 1 1) "subscribe" 2) "sanchan" 3) (integer) 2 1) "subscribe" 2) "news" 3) (integer) 3 1) "subscribe" 2) "test" 3) (integer) 4 # 客户端2 coderknock> SUBSCRIBE coderknock sanchan blog oschina Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "coderknock" 3) (integer) 1 1) "subscribe" 2) "sanchan" 3) (integer) 2 1) "subscribe" 2) "blog" 3) (integer) 3 1) "subscribe" 2) "oschina" 3) (integer) 4 # 统计出的有订阅的频道 coderknock> PUBSUB CHANNELS 1) "coderknock" 2) "sanchan" 3) "blog" 4) "news" 5) "oschina" 6) "test" # 统计频道名包含 o 的频道 coderknock> PUBSUB CHANNELS *o* 1) "coderknock" 2) "blog" 3) "oschina" #咱们关闭客户端1,只有客户端1订阅的 "news" "test" 频道消失 coderknock> PUBSUB CHANNELS 1) "blog" 2) "oschina" 3) "coderknock" 4) "sanchan" # 从新订阅 # 客户端1 coderknock>PSUBSCRIBE news.* coderknock.* Reading messages... (press Ctrl-C to quit) 1) "psubscribe" 2) "news.*" 3) (integer) 1 1) "psubscribe" 2) "coderknock.*" 3) (integer) 2 # 客户端2 coderknock> PSUBSCRIBE sanchan.* coderknock.* Reading messages... (press Ctrl-C to quit) 1) "psubscribe" 2) "sanchan.*" 3) (integer) 1 1) "psubscribe" 2) "coderknock.*" 3) (integer) 2 # 客户端3 coderknock> PSUBSCRIBE sanchan.* coderknock.* news blog Reading messages... (press Ctrl-C to quit) 1) "psubscribe" 2) "sanchan.*" 3) (integer) 1 1) "psubscribe" 2) "coderknock.*" 3) (integer) 2 1) "psubscribe" 2) "news" 3) (integer) 3 1) "psubscribe" 2) "blog" 3) (integer) 4 # 说明不会统计 PSUBSCRIBE 订阅 coderknock> PUBSUB CHANNELS (empty list or set)
返回给定频道的订阅者数量, 订阅模式的客户端不计算在内。
N
为给定频道的数量。channel-1
, channel-1
的订阅者数量,频道 channel-2
, channel-2
的订阅者数量,诸如此类。 回复中频道的排列顺序和执行命令时给定频道的排列顺序一致。 不给定任何频道而直接调用这个命令也是能够的, 在这种状况下, 命令只返回一个空列表。# 订阅的客户端 #客户端1 coderknock> SUBSCRIBE coderknock sanchan blog oschina Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "coderknock" 3) (integer) 1 1) "subscribe" 2) "sanchan" 3) (integer) 2 1) "subscribe" 2) "blog" 3) (integer) 3 1) "subscribe" 2) "oschina" 3) (integer) 4 #客户端2 coderknock> SUBSCRIBE coderknock sanchan news test Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "coderknock" 3) (integer) 1 1) "subscribe" 2) "sanchan" 3) (integer) 2 1) "subscribe" 2) "news" 3) (integer) 3 1) "subscribe" 2) "test" 3) (integer) 4 #客户端3 coderknock> PSUBSCRIBE sanchan.* coderknock.* news blog Reading messages... (press Ctrl-C to quit) 1) "psubscribe" 2) "sanchan.*" 3) (integer) 1 1) "psubscribe" 2) "coderknock.*" 3) (integer) 2 1) "psubscribe" 2) "news" 3) (integer) 3 1) "psubscribe" 2) "blog" 3) (integer) 4 # 统计,能够看到 PSUBSCRIBE 订阅一样不会被统计并且不支持模式匹配 coderknock> PUBSUB NUMSUB coderknock news blog oschina test sanchan coderknock.* 1) "coderknock" 2) (integer) 2 3) "news" 4) (integer) 1 5) "blog" 6) (integer) 1 7) "oschina" 8) (integer) 1 9) "test" 10) (integer) 1 11) "sanchan" 12) (integer) 2 13) "coderknock.*" 14) (integer) 0
返回 订阅模式 的数量。
注意, 这个命令返回的不是订阅模式的客户端的数量, 而是客户端订阅的全部模式的数量总和。
N
为给定频道的数量。#采用上面示例中的订阅客户端,这里统计的 订阅模式 包含 PSUBSCRIBE 订阅 coderknock> PUBSUB NUMPAT (integer) 8 # 添加一个客户端4 coderknock> PSUBSCRIBE blog* Reading messages... (press Ctrl-C to quit) 1) "psubscribe" 2) "blog*" 3) (integer) 1 # 统计会发现模式增长 1 coderknock> PUBSUB NUMPAT (integer) 9
### 退订
#### UNSUBSCRIBE
自2.0.0可用。
时间复杂度:O(N) ,
N
是客户端已订阅的频道的数量。
指示客户端退订给定的频道。
若是没有频道被指定,也便是,一个无参数的 UNSUBSCRIBE
调用被执行,那么客户端使用 SUBSCRIBE
命令订阅的全部频道都会被退订。在这种状况下,命令会返回一个信息,告知客户端全部被退订的频道。
这个命令在不一样的客户端中有不一样的表现。
在命令行中该命令没法测试(订阅后命令行会阻塞),咱们使用 python 进行测试:
import redis import time r = redis.StrictRedis(host='127.0.0.1', password='admin123', port=6379, db=0) p = r.pubsub() p.subscribe("coderknock", "sanchan", "python") """ # 基于上一个命令的示例,此时在客户端中执行 coderknock> PUBSUB CHANNELS 1) "python" 2) "blog" 3) "news" 4) "test" 5) "oschina" 6) "coderknock" 7) "sanchan" # 说明订阅成功 # 统计订阅数量 coderknock> PUBSUB NUMSUB coderknock news blog oschina test sanchan coderknock.* python 1) "coderknock" 2) (integer) 3 3) "news" 4) (integer) 1 5) "blog" 6) (integer) 1 7) "oschina" 8) (integer) 1 9) "test" 10) (integer) 1 11) "sanchan" 12) (integer) 3 13) "coderknock.*" 14) (integer) 0 15) "python" 16) (integer) 1 """ time.sleep(10) # 休眠 10 秒 p.unsubscribe("sanchan") """ # 此时取消了一个 sanchan 的订阅 coderknock> PUBSUB NUMSUB coderknock news blog oschina test sanchan coderknock.* python 1) "coderknock" 2) (integer) 3 3) "news" 4) (integer) 1 5) "blog" 6) (integer) 1 7) "oschina" 8) (integer) 1 9) "test" 10) (integer) 1 11) "sanchan" 12) (integer) 2 13) "coderknock.*" 14) (integer) 0 15) "python" 16) (integer) 1 """ time.sleep(10) # 休眠 10 秒 p.unsubscribe() """ # 此时该 python 中订阅所有退订 coderknock> PUBSUB NUMSUB coderknock news blog oschina test sanchan coderknock.* python 1) "coderknock" 2) (integer) 2 3) "news" 4) (integer) 1 5) "blog" 6) (integer) 1 7) "oschina" 8) (integer) 1 9) "test" 10) (integer) 1 11) "sanchan" 12) (integer) 2 13) "coderknock.*" 14) (integer) 0 15) "python" 16) (integer) 0 """
#### UNSUBSCRIBE
自2.0.0可用。
时间复杂度:O(N+M) ,其中
N
是客户端已订阅的模式的数量,M
则是系统中全部客户端订阅的模式的数量。
指示客户端退订全部给定模式。
若是没有模式被指定,也便是,一个无参数的 PUNSUBSCRIBE
调用被执行,那么客户端使用 PSUBSCRIBE
命令订阅的全部模式都会被退订。在这种状况下,命令会返回一个信息,告知客户端全部被退订的模式
这个命令在不一样的客户端中有不一样的表现。
客户端在执行订阅命令以后进入了订阅状态,只能接收 SUBSCRIBE
、PSUBSCRIBE
、UNSUBSCRIBE
、PUNSUBSCRIBE
四个命令。
开启的订阅客户端,没法收到该频道以前的消息,由于 Redis 不会对发布的消息进行持久化。
和不少专业的消息队列系统(例如Kafka、RocketMQ)相比,Redis的发布订阅略显粗糙,例如没法实现消息堆积和回溯。但胜在足够简单,若是当前场景能够容忍的这些缺点,也不失为一个不错的选择。
聊天室、公告牌、服务之间利用消息解耦均可以使用发布订阅模式
本人的直播课程在 7 月份就要开始了,但愿小伙伴们支持一下,如今报名有优惠噢