Redis的发布/订阅模型(pubsub)

为什么还要发布订阅模型?

前面我们讲了Redis消息队列的使用方法,但是没有提到Redis消息队列的不足。Redis消息队列的一个很大的不足就是无法支持消息的多播机制,正因为如此,Redis才提出了发布订阅模型!

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

PubSub
为了支持消息多播,Redis不能再依赖基本的数据类型实现了,它单独的使用了一个模块来支持消息多播的功能,既PubSub模块, 也就是通常我们所说的发布/订阅模型

发布订阅模型的缺点

离线节点彻底丢失消息
Redis的PubSub模块的生产者发送了一个消息给订阅者,Redis会直接找到订阅的消费者发送。如果一个消费者都没有,那么生产者的消息就相当石沉大海,直接被丢弃。

所以这就会造成一个很大的弊端。当有三个订阅者订阅了一个生产者,突然某个消费者节点离线了,过了一会又上线了。那么在该消费者离线期间,生成者所推送的内容,相对该掉线消费者就是彻底丢失了。
没有消息确认机制

只要消息从Redis的队列中pop出去后,就再也不跟Redis有任何关系了,业务逻辑执行错了,消息也不会回到Redis中。对比RabbitMQ就可以做到,业务执行失败,no-ack,消息会回到Rabbit队列中
无法保证消息真实到达中间件,既消息从发布者客户端发送出现后,是否有到达Redis服务器,是无法知道的。相比RabbitMQ就可以有Comfirm机制
消息不能持久化

因为PubSub的消息并非是Redis的一种数据类型,所以PubSub中数据是没有得到aof等持久化机制的支持的,既一旦节点崩溃,重新上线后,消息是会丢失的。这一点在Redis 5.0的Stream新数据结构中得到了改善
也正因为PubSub模块的这些缺点,在严谨的消息队列领域,Redis的PubSub模型上不了主舞台,只能做一下简单的消息推送功能。总之Redis的发布订阅模块并不能作为严格意义的消息中间件,只能算是一个轻量级消息队列,可以在一些无伤大雅的低要求场景上使用

所以Redis的作者单独开启了一个叫Disque的项目,专门做多播消息队列,但是目前该项目还未成熟。但是更让人劲爆的消息是,Redis5.0新增了一个Stream数据结构,它是一个强大的支持多播的可持久化的消息队列。所以在可预见的未来,PubSub会逐渐被淘汰,Disque项目也可能不会有发行版本了。

发布/订阅模型的命令

  • publish
    将信息 message 发送到指定的频道 channel,返回频道订阅者数量
    publish channel message

  • subscribe

    订阅一个或多个频道
    subscribe channel [channel...]

  • psubscribe
    订阅符合一个或多个匹配模式的所有频道,psubscribe new.* 则是订阅所有new.开头的频道(new.log,new.studnet,etc…)
    psubscribe pattern [pattern …]

  • unsubscribe

    退订一个或多个的指定频道
    unsubscribe channel [channel...]

  • punsubscribe

    退订符合一个或多个匹配模式的所有频道
    punsubcribe pattern [pattern]

  • pubsub

    pubsub是一个查看订阅与发布系统状态的内省命令, 它由数个不同格式的子命令组成pubsub

    • pubsub channels [pattern]查询系统中符合模式的频道信息,pattern为空,则查询系统中所有存在的频道
    • pubsub numsub [channel] 查询一个或多个频道的订阅数
    • pubsub numpat查询当前客户端订阅了多少频道

    我们可以看到本质就是由四种命令组成,发布命令,订阅命令,退订命令和查询命令

消息结构

{
	'type': 'message', 	
	'pattern': None, 
	'channel': ' python.new',
 	'data': 'hello  python ?'
 }

我们可以看到Redis的发布订阅模型中,消息传递的数据结构是有四个固定字段的

  • type

    表示消息的类型
    如果是一个普通的消息,那么类型就是message
    如果是控制消息,比如订阅命令的反馈,那么类型就是subscribe
    如果是模式订阅的返回,它的类型就是psubscribe
    如果是取消订阅的指令,那么就可以是unsubscribe或punsubscribe

  • pattern

    表示当前消息是使用那种模式订阅的,如果是通过subscribe命令订阅的,那么该字段就为空

  • channel

    表示当前订阅的频道名称,其实就相当于kafka的主题,rabbitmq的routing-key

  • data

    这个就很明显的,就是数据体

代码实践

Redis PubSub | Python

发布者

import redis

client = redis.StrictRedis(host='127.0.0.1', port=6379)

# 朝python.new频道发送三条消息
client.publish('python.new', 'hello python?')
client.publish('python.new', "let's learn pythone everyday!!")
client.publish('python.new', "easy python3.7")

订阅者

# 普通版本,利用sleep来阻塞
import redis
import time

client = redis.StrictRedis(host='127.0.0.1', port=6379)

p = client.pubsub()
p.subscribe('python.new')
while True:
    message = p.get_message()
    if not message:
        time.sleep(1)
        continue
    print(message)

# 改良版本,利用listen()来阻塞
import redis
import time

client = redis.StrictRedis(host='127.0.0.1', port=6379)

p = client.pubsub()
p.subscribe('python.new')
for message in p.listen():
    print(message)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值