有些情况,需要用redis消息发布订阅来进行某些服务数据通信,下面是封装的put和get方法
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# project : pythonProject
# filename : redsentpu
# author : ly_13
# date : 4/7/2023
import json
import threading
import time
import redis
from threading import Thread
class RedisMsgCache(object):
def __init__(self, channel):
self.connection_pool = redis.ConnectionPool(host='10.66.8.111', port=6379, db=6, password='nineven')
self.__conn = redis.Redis(connection_pool=self.connection_pool) # 连接redis
self.channel = channel
def put(self, msg):
self.__conn.publish(self.channel, json.dumps(msg)) # 根据提供的频道进行消息发布
return True
def subscribe(self, ):
pub = self.__conn.pubsub() # 打开收音机
pub.subscribe(self.channel) # 调频道
pub.parse_response() # 准备接收
return pub
def get(self):
messages = self.subscribe()
data = messages.parse_response()
try:
return json.loads(data[2])
except:
return data[2]
class MessageXx(RedisMsgCache):
def __init__(self, channel):
super().__init__(channel)
def put_message(x: MessageXx):
while True:
msg = f"{time.time()}"
x.put(msg)
print(f"{threading.currentThread()} 发送消息:{msg}")
time.sleep(1)
def get_message(x: MessageXx):
while True:
print(f"{threading.currentThread()} 获取消息:{x.get()}")
if __name__ == '__main__':
x = MessageXx('test-channel')
# 启动生产者
Thread(target=put_message, args=(x,)).start()
# 启动接受者
Thread(target=get_message, args=(x,)).start()
Thread(target=get_message, args=(x,)).start()
运行打印日志如下:
<Thread(Thread-1, started 7812)> 发送消息:1680926148.241893
<Thread(Thread-2, started 3732)> 获取消息:1680926148.241893
<Thread(Thread-3, started 9764)> 获取消息:1680926148.241893
<Thread(Thread-2, started 3732)> 获取消息:1680926149.2496572
<Thread(Thread-3, started 9764)> 获取消息:1680926149.2496572
<Thread(Thread-1, started 7812)> 发送消息:1680926149.2496572
可以看到,发送消息之后,两个订阅这都会收到消息。
总结
Pub/Sub 最大的优势就是,支持多组生产者、消费者处理消息。但除了这一个优点之外,剩下的都是缺点了
因为 Pub/Sub 的实现原理非常简单,它没有基于任何数据类型,也没有做任何的数据存储,只是单纯地为生产者、消费者建立「数据转发通道」,把符合规则的数据,从一端转发到另一端。
缺点:
- 发布订阅模式是"发后既忘"的工作模式,如果订阅者离线,那么重连之后不能消费之前的历史消息
- 无法持久化保存消息,如果 Redis 服务器宕机或重启,那么所有的消息将会丢失
- 积压的消息不能太多,否则也会丢数据【可以通过client-output-buffer-limit这个参数配置】