Redis随记--pubsub学习

PUBSUB学习

基础知识

在Redis中可以使用LIST来实现简单的消息队列功能,但基于LIST实现的消息队列无法实现"消息多播"的功能。

Redis单独实现PubSub模块来实现"消息多播"功能,并支持模式订阅

常用命令

  • PUBSUB:用于检查消息订阅的状态信息。
  • PUBLIST:将消息传递给特定的Channel。
  • SUBSCRIBE:订阅特定的Channel。
  • PSUBSCRIBE:基于模式订阅匹配该模式的所有Channel。
  • UNSUBSCRIBE:退订特定的Channel。
  • PUNSUBSCRIBE:特对特定模式的所有Channel。

实例代码

发布消息代码:

import time
import datetime
import redis

REDIS_HOST = "xxx.xxx.xxx.xxx"
REDIS_PASSWORD = "xxxxxxxxxxxx"
REDIS_PORT = 6379
REDIS_CHARSET = "utf-8"
PUB_SUB_CHANNEL = "demo_channel"


def pub_demo():
    redis_client = redis.StrictRedis(
        host=REDIS_HOST,
        port=REDIS_PORT,
        password=REDIS_PASSWORD,
        charset=REDIS_CHARSET
    )
    for task_index in range(1, 1000):
        task_msg = "this is task {} at {}".format(
            task_index,
            datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        )
        redis_client.publish(PUB_SUB_CHANNEL, task_msg)
        print(task_msg)
        time.sleep(1)


if __name__ == '__main__':
    pub_demo()

使用监听方式订阅消息代码:

import redis

REDIS_HOST = "xxx.xxx.xxx.xxx"
REDIS_PASSWORD = "xxxxxxxxxxxx"
REDIS_PORT = 6379
REDIS_CHARSET = "utf-8"
PUB_SUB_CHANNEL = "demo_channel"


def sub_demo():
    redis_client = redis.StrictRedis(
        host=REDIS_HOST,
        port=REDIS_PORT,
        password=REDIS_PASSWORD,
        charset=REDIS_CHARSET
    )
    sub_handler = redis_client.pubsub()
    sub_handler.subscribe(PUB_SUB_CHANNEL)
    for sub_msg in sub_handler.listen():
        if sub_msg["type"] == "subscribe":
            print("start to subscribe message")
        if sub_msg["type"] == "message":
            print("task message:{}".format(
                str(sub_msg["data"], encoding="utf-8")
            ))


if __name__ == '__main__':
    sub_demo()

使用定期轮循方式订阅消息:

import redis
import time

REDIS_HOST = "xxx.xxx.xxx.xxx"
REDIS_PASSWORD = "xxxxxxxxxxxx"
REDIS_PORT = 6379
REDIS_CHARSET = "utf-8"
PUB_SUB_CHANNEL = "demo_channel"


def sub_demo():
    redis_client = redis.StrictRedis(
        host=REDIS_HOST,
        port=REDIS_PORT,
        password=REDIS_PASSWORD,
        charset=REDIS_CHARSET
    )
    sub_handler = redis_client.pubsub()
    sub_handler.subscribe(PUB_SUB_CHANNEL)
    while True:
        sub_msg = sub_handler.get_message()
        if sub_msg is None:
            time.sleep(1)
            continue
        if sub_msg["type"] == "subscribe":
            print("start to subscribe message")
        if sub_msg["type"] == "message":
            print("task message:{}".format(
                str(sub_msg["data"], encoding="utf-8")
            ))


if __name__ == '__main__':
    sub_demo()

运行发布消息产生的结果:

(venv) H:\GGA_CODE\pubsub_demo>python pub_demo.py
this is task 1 at 2021-02-28 20:39:06
this is task 2 at 2021-02-28 20:39:07
this is task 3 at 2021-02-28 20:39:08
this is task 4 at 2021-02-28 20:39:09
this is task 5 at 2021-02-28 20:39:10
this is task 6 at 2021-02-28 20:39:11
this is task 7 at 2021-02-28 20:39:13
this is task 8 at 2021-02-28 20:39:14
this is task 9 at 2021-02-28 20:39:15

运行订阅消息产生的结果(早于发布运行):

(venv) H:\GGA_CODE\pubsub_demo>python sub_loop_demo.py
start to subscribe message
task message:this is task 1 at 2021-02-28 20:39:06
task message:this is task 2 at 2021-02-28 20:39:07
task message:this is task 3 at 2021-02-28 20:39:08
task message:this is task 4 at 2021-02-28 20:39:09
task message:this is task 5 at 2021-02-28 20:39:10
task message:this is task 6 at 2021-02-28 20:39:11
task message:this is task 7 at 2021-02-28 20:39:13
task message:this is task 8 at 2021-02-28 20:39:14
task message:this is task 9 at 2021-02-28 20:39:15

运行订阅消息产生的结果(晚于发布运行):

(venv) H:\GGA_CODE\pubsub_demo>python sub_listen_demo.py
start to subscribe message
task message:this is task 5 at 2021-02-28 20:39:10
task message:this is task 6 at 2021-02-28 20:39:11
task message:this is task 7 at 2021-02-28 20:39:13
task message:this is task 8 at 2021-02-28 20:39:14
task message:this is task 9 at 2021-02-28 20:39:15

总结:

  • Python客户端支持lister和get_message两种方式订阅消息,区别在于是否阻塞方式调用parse_response方法。
  • Redis支持多用户订阅相同Channel,订阅的程序能收到从建立订阅连接开始的消息,建立连接前发布的消息会丢失。
def listen(self):
	"Listen for messages on channels this client has been subscribed to"
	while self.subscribed:
		response = self.handle_message(self.parse_response(block=True))
		if response is not None:
			yield response

def get_message(self, ignore_subscribe_messages=False, timeout=0):
	"""
	Get the next message if one is available, otherwise None.

	If timeout is specified, the system will wait for `timeout` seconds
	before returning. Timeout should be specified as a floating point
	number.
	"""
	response = self.parse_response(block=False, timeout=timeout)
	if response:
		return self.handle_message(response, ignore_subscribe_messages)
	return None

学习总结

Redis的PubSub模块实现简单的发布订阅功能,支持消息多播,但PubSub模块不支持消息持久化,消费者断连期间的消息会丢失,同时PubSub也不支持消费组和消息确认等功能,导致在生产环境很难有场景可以使用PubSub模块。

posted @ 2021-02-28 21:04  TeyGao  阅读(119)  评论(0编辑  收藏  举报