引入
我们知道,redis可以用作消息队列,但是redis消息队列有个不足之处,那就是它不支持消息的多播机制。而redis的发布PubSub 模式可以解决这个问题。
什么叫做消息的多播
消息多播允许生产者只生产一次消息,由中间件负责将消息复制到多个消息队列,每个消息队列由相应的消费组进行消费。如下图。
- 它是分布式系统常用的一种解耦方式,用于将多个消费者的逻辑进行拆分。支持了消息多播,多个消费组的逻辑可以放到不同的系统中
- 如果是普通的消息队列,就需要将不同的消息组逻辑串在一起放在一个子系统中,进行连续消费
发布/订阅
- Redis PubSub 模块又称发布订阅者模式,是一种消息传递系统,实现了消息多播功能。
- 此种模式下,消息发布者和订阅者不进行直接通信,发布者客户端向指定的频道(channel)发布消息,订阅该频道的每个客户端都可以收到该消息。
- 发布者(即发送方)发送消息,订阅者(即接收方)接收消息,而用来传递消息的链路则被称为 channel。
- 在 Redis 中,一个客户端可以订阅任意数量的 channel(可译为频道)
常用命令
publish:发布消息
作用
Redis Publish 命令用于将信息发送到指定的频道。
语法
redis 127.0.0.1:6379> PUBLISH channel message
返回值
接收到信息的订阅者数量。
实例
redis 127.0.0.1:6379> PUBLISH mychannel "hello, i m here"
(integer) 1
subscribe:订阅消息
作用
订阅者可以通过这个命令订阅给定的一个或多个频道的信息
语法
redis 127.0.0.1:6379> SUBSCRIBE channel [channel ...]
返回值
接收到的信息
实例
实例
127.0.0.1:6379> subscribe channel:sports
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel:sports"
3) (integer) 1
...此处是等待中
在另一个客户端发布一条消息:
127.0.0.1:6379> publish channel:sports "The Timberwolves win the Lakers" -
(integer) 1
当前订阅者会收到消息:
127.0.0.1:6379> subscribe channel:sports
Reading messages... (press Ctrl-C to quit)
...
1) "message" #消息
2) "channel:sports" #频道
3) "The Timberwolves win the Lakers" #内容
有关订阅命令有两点需要注意:
- 客户端在执行订阅命令之后进入订阅状态,只能接收subscribe、pubscribe、unsubscribe、pinsubscribe四个命令;
- 新开启的订阅客户端,无法接收到该频道之前的消息,因为Redis不会对发布的消息持久化
unsubscribe:退订指定频道
作用
客户端可以通过unsubscribe命令取消对指定频道的订阅,取消成功后,不会再收到该频道发布的消息
语法
redis 127.0.0.1:6379> UNSUBSCRIBE channel [channel ...]
返回值
这个命令在不同的客户端中有不同的表现。
实例
redis 127.0.0.1:6379> UNSUBSCRIBE mychannel
1) "unsubscribe"
2) "a"
3) (integer) 0
psubscribe :按照模式订阅消息
作用
Redis Psubscribe 命令订阅一个或多个符合给定模式的频道。
每个模式以 *
作为匹配符
- 比如
it*
匹配所有以 it 开头的频道( it.news 、 it. it.tweets 等等)。 -
news.*
匹配所有以 news. 开头的频道( news.it 、 news.global.today 等等),诸如此类。
语法
redis 127.0.0.1:6379> PSUBSCRIBE pattern [pattern ...]
返回值
接收到的信息。
实例
订阅指定模式的频道,*代表通配符,会匹配所有www开头的频道
127.0.0.1:6379> PSUBSCRIBE www*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "www*"
3) (integer) 1
#按ctrl+c退出阻塞状态
^C
punsubscribe :退订指定模式的频道
作用
Redis Punsubscribe 命令用于退订所有给定模式的频道。
语法
redis 127.0.0.1:6379> PUNSUBSCRIBE [pattern [pattern ...]]
返回值
这个命令在不同的客户端中有不同的表现。
实例
127.0.0.1:6379> PUNSUBSCRIBE www*
1) "punsubscribe"
2) "www*"
3) (integer) 0
redis 127.0.0.1:6379> PUNSUBSCRIBE mychannel
1) "punsubscribe"
2) "a"
3) (integer) 1
pubsub :查询订阅
作用
Redis Pubsub 命令用于查看订阅与发布系统状态,它由数个不同格式的子命令组成。
语法
redis 127.0.0.1:6379> PUBSUB <subcommand> [argument [argument ...]]
返回值
由活跃频道组成的列表。
实例
查看活跃的频道:
pubsub channels [pattern]
所谓活跃的频道是指当前频道至少有一个订阅者,其中[pattern]是可以指定具体的模式:
127.0.0.1:6379> pubsub channels
1) "write"
2) "water"
查看频道的订阅数:
pubsub numsub [channel ... ]
返回某一个频道的订阅数:
127.0.0.1:6379> pubsub numsub write
1) "write"
2) (integer) 1 #订阅数为1
查看模式订阅数:
pubsub numpat
127.0.0.1:6379> pubsub numpat #当前没有模式订阅的用户
(integer) 0
案例
订阅者/等待接收消息
首先打开 Redis 客户端,然后订阅了一个名为“www.biancheng.net”的 channel,使用如下命令:
#订阅channel
127.0.0.1:6379> SUBSCRIBE www.biancheng.net
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "www.biancheng.net"
3) (integer) 1
上述示例使用SUBSCRIBE命令订阅了名为 www.biancheng.net 的 channel。命令执行后该客户端会出处于等待接收消息的阻塞状态。
发布者/发送消息
下面再启动一个 Redis 客户端,输入如下命令:
127.0.0.1:6379> PUBLISH www.biancheng.net "this is website"
(integer) 1
127.0.0.1:6379> PUBLISH www.biancheng.net "hello world"
(integer) 1
127.0.0.1:6379> PUBLISH www.biancheng.net "how are you"
(integer) 1
通过上述PUBLISH命令发布了三条信息。现在两个客户端在处于同一个名为“www.biancheng.net”的频道上,前者负责接收消息,后者负责发布消息。
订阅者/成功接收消息
在接收消息的客户端j:
127.0.0.1:6379> SUBSCRIBE www.biancheng.net
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "www.biancheng.net"
3) (integer) 1
1) "message"
2) "www.biancheng.net"
3) "this is website"
1) "message"
2) "www.biancheng.net"
3) "hello world"
1) "message"
2) "www.biancheng.net"
3) "how are you"
pubsub的缺点
- pubsub的生产者传递过来一个消息,redis会直接找到相应的消费者传递过去。如果一个消费者都没有,那么消息会被直接丢弃调。如果开始有三个消费者,一个消费者突然down了,生产者会继续发送消息,另外两个消费者可以持续收到消息,但是当前挂掉的消费者重新连上时,在断连期间生产者发送的消息,对于这个消费者来说就是彻底丢失了
- 如果redis停机重启,pubsub的消息是不会持久化的,比较redis宕机就相当于一个消费者都没有,所有的消息都会被直接丢弃
- 正是因为pubsub有这些缺点,在消息队列的领域它几乎找不到何时的应用场景,所以redis的作者单独开来一个项目Disque专门用来做多播消息队列,不过该项目没有成熟,一直出于beta版本
- 2018年6月,redis5.0新增了stream数据结构,这个功能给redis带来了持久化的消息队列,从此pubsub作为消息队列的功用可以消息了,disque估计永远也不会release了