引入

我们知道,redis可以用作消息队列,但是redis消息队列有个不足之处,那就是它不支持消息的多播机制。而redis的发布PubSub 模式可以解决这个问题。

什么叫做消息的多播

消息多播允许生产者只生产一次消息,由中间件负责将消息复制到多个消息队列,每个消息队列由相应的消费组进行消费。如下图。

  • 它是分布式系统常用的一种解耦方式,用于将多个消费者的逻辑进行拆分。支持了消息多播,多个消费组的逻辑可以放到不同的系统中
  • 如果是普通的消息队列,就需要将不同的消息组逻辑串在一起放在一个子系统中,进行连续消费

redis接入promethus redis pubsub_客户端

发布/订阅

  • Redis PubSub 模块又称发布订阅者模式,是一种消息传递系统,实现了消息多播功能。
  • 此种模式下,消息发布者和订阅者不进行直接通信,发布者客户端向指定的频道(channel)发布消息,订阅该频道的每个客户端都可以收到该消息。
  • 发布者(即发送方)发送消息,订阅者(即接收方)接收消息,而用来传递消息的链路则被称为 channel。
  • 在 Redis 中,一个客户端可以订阅任意数量的 channel(可译为频道)

redis接入promethus redis pubsub_redis接入promethus_02

常用命令

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了