简介
发布/ 订阅系统 是 Web 系统中比较常用的一个功能。简单点说就是 发布者发布消息,订阅者接受消息;
为了支持消息多播,Redis 不能再依赖于那 5 种基础的数据结构了,它单独使用了一个模块来支持消息多播,这个模块就是 PubSub,也就是 PublisherSubscriber (发布者/ 订阅者模式)。
在 Redis 中,PubSub 模块的使用非常简单,常用的命令也就下面这么几条:
# 订阅频道:
SUBSCRIBE channel [channel ....] # 订阅给定的一个或多个频道的信息
PSUBSCRIBE pattern [pattern ....] # 订阅一个或多个符合给定模式的频道
# 发布频道:
PUBLISH channel message # 将消息发送到指定的频道
# 退订频道:
UNSUBSCRIBE [channel [channel ....]] # 退订指定的频道
PUNSUBSCRIBE [pattern [pattern ....]] #退订所有给定模式的频道
PubSub 的缺点
尽管 Redis 实现了 PubSub 模式来达到了 多播消息队列 的目的,但在实际的消息队列的领域,几乎 找不到特别合适的场景,因为它的缺点十分明显:
- 没有 Ack 机制,也不保证数据的连续: PubSub 的生产者传递过来一个消息,Redis 会直接找到相应的消费者传递过去。如果没有一个消费者,那么消息会被直接丢弃。如果开始有三个消费者,其中一个突然挂掉了,过了一会儿等它再重连时,那么重连期间的消息对于这个消费者来说就彻底丢失了。
- 不持久化消息: 如果 Redis 停机重启,PubSub 的消息是不会持久化的,毕竟 Redis 宕机就相当于一个消费者都没有,所有的消息都会被直接丢弃。
python demo:
发布者
import redis
DB_REDIS = {'host': '127.0.0.1', 'port': 6379, 'db': 0, }
key = 'listen_1'
number_list = ['a', 'b', 'c', 'd']
signal = ['A', 'B', 'C', 'D']
red = redis.StrictRedis(**DB_REDIS)
for i, number in enumerate(number_list):
value_new = f'{number} {signal[i]}'
red.publish(key, value_new)
订阅者
import redis
DB_REDIS = {'host': '127.0.0.1', 'port': 6379, 'db': 0, }
key = 'listen_1'
red = redis.StrictRedis(**DB_REDIS)
ps = red.pubsub()
ps.subscribe(key)
for item in ps.listen():
if item['type'] == 'message':
item['data'].decode()