哈喽大家好~歪小王又来分享了。前段时间因为要解决一下脚本异步执行的问题,所以学了一下消息队列,也成功解决问题。今天就把所学的整理一下做个分享
开篇
先啰嗦一下背景,前两天在使用脚本进行接口扫描的时候,由于一个服务的接口数量过多,在生成用例的时候,后端逻辑处理耗时比较长,所以前端在没等到后端的返回之前,就页面超时了
未解决这个问题,就首先想到了异步执行,然后就跟chatgpt亲密的沟通了一番,决定B站淘两个视频,学习一下消息队列跟celery
消息队列大家都知道。是处理异步、削锋非常好用的一个中间件。代表作有rabbitMQ和kafuka
celery是python的一个第三方工具。它封装了消息中间件。使python使用队列更方便简介
rabbitMQ
就那rabbitMQ来说。MQ的队列模式常用的模式有简单模式与交换机模式;简单的配置下环境,python直接操作mq的话,需要下载一个pika的包。然后使用docker pull rabbitmq 安装下mq并完成相应的ip映射
简单模式:
如其名,比较简单的一种模式,直接去创建链接,然后分发任务;分发任务是轮询分发。生产者可以生产一批数据后,分发给消费者队列中空闲的成员。如果第一个被发配过任务,才会发给第二个
生产者
import pika # 创建连接 connection = pika.BlockingConnection( pika.ConnectionParameters("localhost")) # 获取频道对象 channel = connection.channel() # 创建队列 参数:队列名称.尽量唯一 channel.queue_declare(queue="hello") # 向指定队列插入数据 # 参数exchange:交换机模式 # 参数routing_key:指定队列 # 参数body:向指定队列插入数据 channel.basic_publish(exchange="", routing_key="hello", body="Hello World")
消费者
connection = pika.BlockingConnection( pika.ConnectionParameters(host="0.0.0.0", port=5673)) # 获取频道对象 channel = connection.channel() # 创建队列 参数:队列名称.尽量唯一 # 为什么还需要创建一个队列,应为不确定生产者先运行还是消费者先运行。防止报错所以这里也会创建 channel.queue_declare(queue="hello") # 定义回调函数 # body 是从队列接收到的参数 def callback(ch, method, properties, body): print(f"ccc{body}") # 监听队列 # auto_ack:应答参数.默认应答 channel.basic_consume(queue="hello", auto_ack=True, on_message_callback=callback) # 运行监听 channel.start_consuming()
参数使用
如果mq队列崩坏,也会造成数据丢失,此时可以通过将数据放进硬盘,来解决这个问题。 创建可持久化队列。 创建队列时,添加参:durable=True。 并且在插入数据时,添加如下参数
mq的分法是按照轮询分法的。在实际项目中,无法合理利用资源。可以将这种轮询模式改为公平模式 在消费者中修改轮训配置为公平模式:channel.basic_qos(prefetch_count=1)
auto_ack:默认应答---》true开启。false关闭 需要注意的是:如果设置成自动应答的话,会造成数据丢失的情况。为解决这类问题。需要将自动应答改为手动应答。同时,在消费者的回调函数里面如下代码
应答参数
分发参数
持久化参数
交换机模式
交换机模式,相比简单模式,功能要强大的多,简单模式只能给单一消费者发送数据,交换机模式可以完成一对多的消息发送。另外,他还包含了发布订阅、关键字模式。他们的生产者跟消费者与简单模式有如下区别:
再来说下发布订阅与关键字模式
发布订阅模式下的生产者
# 创建连接 connection = pika.BlockingConnection( pika.ConnectionParameters(host="0.0.0.0", port=5673)) # 获取频道对象 channel = connection.channel() # 创建交换机 # 参数exchange:交换机名称 # 参数exchange_type:模式--->fanout发布订阅模式 channel.exchange_declare(exchange="logs", exchange_type="fanout") # 向指定队列插入数据 # 参数exchange:交换机模式.绑定创建的交换机 # 参数routing_key:指定队列.如果是交换机模式.该参数为空 # 参数body:向指定队列插入数据 channel.basic_publish(exchange="logs", routing_key="", body="123321123123") # 关闭链接 connection.close()
发布订阅模式下的消费者
# 创建连接 connection = pika.BlockingConnection( pika.ConnectionParameters(host="0.0.0.0", port=5673)) # 获取频道对象 channel = connection.channel() channel.exchange_declare(exchange="logs", exchange_type="fanout") # 创建队列.并给定一个随机名称 result = channel.queue_declare("", exclusive=True) # 获取队列名称 queue_name = result.method.queue # 定义回调函数 # body 是从队列接收到的参数 def callback(ch, method, properties, body): print(f"ccc{body}") # 将指定队列绑定到指定的交换机 channel.queue_bind(queue=queue_name, exchange="logs") # 监听队列 # auto_ack:应答参数.默认应答 channel.basic_consume(queue=queue_name, auto_ack=True, on_message_callback=callback) # 运行监听 channel.start_consuming()
关键字模式:比发布订阅范围更大的一种模式。可以绑定一个关键字,消费者同时绑定这个关键字。生产者在发布的数据中包含该关键字的数据都会发送给绑定这个关键字的消费者
发布订阅:犹如专属订阅一样,生产者发布一批数据后,数据会发送到指定的消费者手中
生产者:相比简单模式,交换机模式会先创建一个交换机,而不去创建队列。然后生产者往交换机里面插入数据。
消费者:自己创建队列,然后绑定交换机。
关键字模式下的生产者
import pika
connection = pika.BlockingConnection(
pika.ConnectionParameters(host="0.0.0.0", port=5673))
# 获取频道对象
channel = connection.channel()
# 创建交换机
# 参数exchange:交换机名称
# 参数exchange_type:模式--->direct关键字模式
channel.exchange_declare(exchange="logs2",
exchange_type="direct")
# 向指定队列插入数据
# 参数exchange:交换机模式.绑定创建的交换机
# 参数routing_key:在普通模式下为指定队列.如果是交换机模式-发布订阅模式下,该参数为空
# 如果是交换机模式-关键字模式下.该参数为绑定的关键字
# 参数body:向指定队列插入数据
channel.basic_publish(exchange="logs2",
routing_key="warning",
body="this is warning")
# 关闭链接
connection.close()
关键字模式下的消费者
import pika
# 创建连接
connection = pika.BlockingConnection(
pika.ConnectionParameters(host="0.0.0.0", port=5673))
# 获取频道对象
channel = connection.channel()
channel.exchange_declare(exchange="logs2",
exchange_type="direct")
# 创建队列.并给定一个随机名称
result = channel.queue_declare("", exclusive=True)
# 获取队列名称
queue_name = result.method.queue
# 定义回调函数
# body 是从队列接收到的参数
def callback(ch, method, properties, body):
print(f"ccc{body}")
# 绑定制定队列的指定关键字参数
channel.queue_bind(queue=queue_name,
exchange="logs2",
routing_key="warning")
# 监听队列
# auto_ack:应答参数.默认应答
channel.basic_consume(queue=queue_name,
auto_ack=True,
on_message_callback=callback)
# 运行监听
channel.start_consuming()
以上就简单介绍一下mq的工作模式以及每种模式下可以使用的方法。在关键字模式下还有一个模糊匹配模式,感兴趣的小伙伴可以百度搜索一波。很简单
结语
由于篇幅问题。本期内容就先到这里。下期内容会分享一下celery的使用。简直就是神器。上面这个花里胡哨的内容。一两行代码就可以搞定
各位大佬。小王先退下了~拜拜~