python队列通信:rabbitMQ的使用(实例讲解)


Posted in Python onDecember 22, 2017

(一)、前言

为什么引入消息队列?

1.程序解耦

2.提升性能

3.降低多业务逻辑复杂度

(二)、python操作rabbit mq

rabbitmq配置安装基本使用参见上节文章,不再复述。

若想使用python操作rabbitmq,需安装pika模块,直接pip安装:

pip install pika

1.最简单的rabbitmq producer端与consumer端对话:

producer:

#Author :ywq
import pika
auth=pika.PlainCredentials('ywq','qwe') #save auth indo
connection = pika.BlockingConnection(pika.ConnectionParameters(
  '192.168.0.158',5672,'/',auth)) #connect to rabbit
channel = connection.channel() #create channel
channel.queue_declare(queue='hello') #declare queue
#n RabbitMQ a message can never be sent directly to the queue, it always needs to go through an exchange.
channel.basic_publish(exchange='',
   routing_key='hello',
   body='Hello World!') #the body is the msg content
print(" [x] Sent 'Hello World!'")
connection.close()

consumer:

#Author :ywq
import pika
auth=pika.PlainCredentials('ywq','qwe') #auth info
connection = pika.BlockingConnection(pika.ConnectionParameters(
  '192.168.0.158',5672,'/',auth)) #connect to rabbit
channel = connection.channel()  #create channel

channel.queue_declare(queue='hello') #decalre queue
def callback(ch, method, properties, body):
 print(" [x] Received %r" % body)

channel.basic_consume(callback,
   queue='hello',
   no_ack=True)
print(' [*] Waiting for messages. To exit press CTRL+C')
channel.start_consuming()

消息传递消费过程中,可以在rabbit web管理页面实时查看队列消息信息。

python队列通信:rabbitMQ的使用(实例讲解)

2.持久化的消息队列,避免宕机等意外情况造成消息队列丢失。

consumer端无需改变,在producer端代码内加上两个属性,分别使消息持久化、队列持久化,只选其一还是会出现消息丢失,必须同时开启:

delivery_mode=2 #make msg persisdent
durable=True

属性插入位置见如下代码(producer端):

#Author :ywq
import pika,sys
auth_info=pika.PlainCredentials('ywq','qwe')
connection=pika.BlockingConnection(pika.ConnectionParameters(
  '192.168.0.158',5672,'/',auth_info
 ))
channel=connection.channel()
channel.queue_declare(queue='test1',durable=True) #durable=Ture, make queue persistent

msg=''.join(sys.argv[1:]) or 'Hello'
channel.basic_publish(
 exchange='',
 routing_key='test1',
 body=msg,
 properties=pika.BasicProperties(
  delivery_mode=2 #make msg persisdent
 )
)

print('Send done:',msg)
connection.close()

3.公平分发

在多consumer的情况下,默认rabbit是轮询发送消息的,但有的consumer消费速度快,有的消费速度慢,为了资源使用更平衡,引入ack确认机制。consumer消费完消息后会给rabbit发送ack,一旦未ack的消息数量超过指定允许的数量,则不再往该consumer发送,改为发送给其他consumer。

producer端代码不用改变,需要给consumer端代码插入两个属性:

channel.basic_qos(prefetch_count= *) #define the max non_ack_count
channel.basic_ack(delivery_tag=deliver.delivery_tag) #send ack to rabbitmq

属性插入位置见如下代码(consumer端):

#Author :ywq
import pika,time
auth_info=pika.PlainCredentials('ywq','qwe')
connection=pika.BlockingConnection(pika.ConnectionParameters(
 '192.168.0.158',5672,'/',auth_info
 )
)
channel=connection.channel()
channel.queue_declare(queue='test2',durable=True)
def callback(chann,deliver,properties,body):
 print('Recv:',body)
 time.sleep(5)
 chann.basic_ack(delivery_tag=deliver.delivery_tag) #send ack to rabbit
channel.basic_qos(prefetch_count=1)
'''
注意,no_ack=False 注意,这里的no_ack类型仅仅是告诉rabbit该消费者队列是否返回ack,若要返回ack,需要在callback内定义
prefetch_count=1,未ack的msg数量超过1个,则此consumer不再接受msg,此配置需写在channel.basic_consume上方,否则会造成non_ack情况出现。
'''
channel.basic_consume(
 callback,
 queue='test2'
)

channel.start_consuming()

三、消息发布/订阅

上方的几种模式都是producer端发送一次,则consumer端接收一次,能不能实现一个producer发送,多个关联的consumer同时接收呢?of course,rabbit支持消息发布订阅,共支持三种模式,通过组件exchange转发器,实现3种模式:

python队列通信:rabbitMQ的使用(实例讲解)

fanout: 所有bind到此exchange的queue都可以接收消息,类似广播。

direct: 通过routingKey和exchange决定的哪个唯一的queue可以接收消息,推送给绑定了该queue的consumer,类似组播。

topic:所有符合routingKey(此时可以是一个表达式)的routingKey所bind的queue可以接收消息,类似前缀列表匹配路由。

1.fanout

publish端(producer):

#Author :ywq
import pika,sys,time
auth_info=pika.PlainCredentials('ywq','qwe')
connection=pika.BlockingConnection(pika.ConnectionParameters(
 '192.168.0.158',5672,'/',auth_info
 )
)
channel=connection.channel()
channel.exchange_declare(exchange='hello',
    exchange_type='fanout'
    )
msg=''.join(sys.argv[1:]) or 'Hello world %s' %time.time()
channel.basic_publish(
 exchange='hello',
 routing_key='',
 body=msg,
 properties=pika.BasicProperties(
 delivery_mode=2
 )
)
print('send done')
connection.close()

subscribe端(consumer):

#Author :ywq
import pika
auth_info=pika.PlainCredentials('ywq','qwe')
connection=pika.BlockingConnection(pika.ConnectionParameters(
 '192.168.0.158',5672,'/',auth_info
 )
)
channel=connection.channel()
channel.exchange_declare(
 exchange='hello',
 exchange_type='fanout'
)
random_num=channel.queue_declare(exclusive=True) #随机与rabbit建立一个queue,comsumer断开后,该queue立即删除释放
queue_name=random_num.method.queue
channel.basic_qos(prefetch_count=1)
channel.queue_bind(
 queue=queue_name,
 exchange='hello'
)
def callback(chann,deliver,properties,body):
 print('Recv:',body)
 chann.basic_ack(delivery_tag=deliver.delivery_tag) #send ack to rabbit

channel.basic_consume(
 callback,
 queue=queue_name,
)
channel.start_consuming()

实现producer一次发送,多个关联consumer接收。

使用exchange模式时:

1.producer端不再申明queue,直接申明exchange

2.consumer端仍需绑定队列并指定exchange来接收message

3.consumer最好创建随机queue,使用完后立即释放。

随机队列名在web下可以检测到:

python队列通信:rabbitMQ的使用(实例讲解)

2.direct

python队列通信:rabbitMQ的使用(实例讲解)

使用exchange同时consumer有选择性的接收消息。队列绑定关键字,producer将数据根据关键字发送到消息exchange,exchange根据 关键字 判定应该将数据发送至指定队列,consumer相应接收。即在fanout基础上增加了routing key.

producer:

#Author :ywq
import pika,sys
auth_info=pika.PlainCredentials('ywq','qwe')
connection=pika.BlockingConnection(pika.ConnectionParameters(
 '192.168.0.158',5672,'/',auth_info
 )
)
channel=connection.channel()
channel.exchange_declare(exchange='direct_log',
   exchange_type='direct',
   )
while True:
 route_key=input('Input routing key:')
 msg=''.join(sys.argv[1:]) or 'Hello'
 channel.basic_publish(
 exchange='direct_log',
 routing_key=route_key,
 body=msg,
 properties=pika.BasicProperties(
  delivery_mode=2
 )
 )
connection.close()

consumer:

#Author :ywq
import pika,sys
auth_info=pika.PlainCredentials('ywq','qwe')
connection=pika.BlockingConnection(pika.ConnectionParameters(
 '192.168.0.158',5672,'/',auth_info
))
channel=connection.channel()
channel.exchange_declare(
 exchange='direct_log',
 exchange_type='direct'
)
queue_num=channel.queue_declare(exclusive=True)
queue_name=queue_num.method.queue
route_key=input('Input routing key:')

channel.queue_bind(
 queue=queue_name,
 exchange='direct_log',
 routing_key=route_key
)
def callback(chann,deliver,property,body):
 print('Recv:[level:%s],[msg:%s]' %(route_key,body))
 chann.basic_ack(delivery_tag=deliver.delivery_tag)

channel.basic_qos(prefetch_count=1)
channel.basic_consume(
 callback,
 queue=queue_name
)
channel.start_consuming()

同时开启多个consumer,其中两个接收notice,两个接收warning,运行效果如下:

python队列通信:rabbitMQ的使用(实例讲解)

3.topic

python队列通信:rabbitMQ的使用(实例讲解)

相较于direct,topic能实现模糊匹配式工作方式(在consumer端指定匹配方式),只要routing key包含指定的关键字,则将该msg发往绑定的queue上。

rabbitmq通配符规则:

符号“#”匹配一个或多个词,符号“”匹配一个词。因此“abc.#”能够匹配到“abc.m.n”,但是“abc.*‘' 只会匹配到“abc.m”。‘.'号为分割符。使用通配符匹配时必须使用‘.'号分割。

producer:

#Author :ywq
import pika,sys
auth_info=pika.PlainCredentials('ywq','qwe')
connection=pika.BlockingConnection(pika.ConnectionParameters(
 '192.168.0.158',5672,'/',auth_info
 )
)
channel=connection.channel()
channel.exchange_declare(exchange='topic_log',
   exchange_type='topic',
   )
while True:
 route_key=input('Input routing key:')
 msg=''.join(sys.argv[1:]) or 'Hello'
 channel.basic_publish(
 exchange='topic_log',
 routing_key=route_key,
 body=msg,
 properties=pika.BasicProperties(
  delivery_mode=2
 )
 )
connection.close()

consumer:

#Author :ywq
import pika,sys
auth_info=pika.PlainCredentials('ywq','qwe')
connection=pika.BlockingConnection(pika.ConnectionParameters(
 '192.168.0.158',5672,'/',auth_info
))
channel=connection.channel()
channel.exchange_declare(
 exchange='topic_log',
 exchange_type='topic'
)
queue_num=channel.queue_declare(exclusive=True)
queue_name=queue_num.method.queue
route_key=input('Input routing key:')

channel.queue_bind(
 queue=queue_name,
 exchange='topic_log',
 routing_key=route_key
)
def callback(chann,deliver,property,body):
 print('Recv:[type:%s],[msg:%s]' %(route_key,body))
 chann.basic_ack(delivery_tag=deliver.delivery_tag)

channel.basic_qos(prefetch_count=1)
channel.basic_consume(
 callback,
 queue=queue_name
)
channel.start_consuming()

运行效果:

python队列通信:rabbitMQ的使用(实例讲解)

rabbitmq三种publish/subscribe模型简单介绍完毕。

以上这篇python队列通信:rabbitMQ的使用(实例讲解)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python中使用百度音乐搜索的api下载指定歌曲的lrc歌词
Jul 18 Python
Python中time模块与datetime模块在使用中的不同之处
Nov 24 Python
Window10+Python3.5安装opencv的教程推荐
Apr 02 Python
Python爬虫框架scrapy实现downloader_middleware设置proxy代理功能示例
Aug 04 Python
pytorch permute维度转换方法
Dec 14 Python
Python----数据预处理代码实例
Mar 20 Python
python基于property()函数定义属性
Jan 22 Python
详解Ubuntu环境下部署Django+uwsgi+nginx总结
Apr 02 Python
Python matplotlib实时画图案例
Apr 23 Python
python实现简单的五子棋游戏
Sep 01 Python
python 写一个文件分发小程序
Dec 05 Python
python实现b站直播自动发送弹幕功能
Feb 20 Python
python3写爬取B站视频弹幕功能
Dec 22 #Python
机器学习经典算法-logistic回归代码详解
Dec 22 #Python
利用python将xml文件解析成html文件的实现方法
Dec 22 #Python
python实现数据预处理之填充缺失值的示例
Dec 22 #Python
NetworkX之Prim算法(实例讲解)
Dec 22 #Python
Python实现控制台中的进度条功能代码
Dec 22 #Python
Python中的探索性数据分析(功能式)
Dec 22 #Python
You might like
模仿OSO的论坛(三)
2006/10/09 PHP
别人整理的服务器变量:$_SERVER
2006/10/20 PHP
简单的移动设备检测PHP脚本代码
2011/02/19 PHP
php之Smarty模板使用方法示例详解
2014/07/08 PHP
微信公众平台之快递查询功能用法实例
2015/04/14 PHP
yii2中dropDownList实现二级和三级联动写法
2017/04/26 PHP
laravel接管Dingo-api和默认的错误处理方式
2019/10/25 PHP
JavaScript 继承详解(四)
2009/07/13 Javascript
改善用户体验的五款jQuery插件分享
2011/05/22 Javascript
JavaScript自定义方法实现trim()、Ltrim()、Rtrim()的功能
2013/11/03 Javascript
JS 去除Array中的null值示例代码
2013/11/20 Javascript
最精简的JavaScript实现鼠标拖动效果的方法
2015/05/11 Javascript
bootstrap布局中input输入框右侧图标点击功能
2016/05/16 Javascript
javascript实现简单的on事件绑定
2016/08/23 Javascript
微信小程序后台解密用户数据实例详解
2017/06/28 Javascript
vue中slot(插槽)的介绍与使用
2018/11/12 Javascript
基于JS实现前端压缩上传图片的实例代码
2019/05/14 Javascript
Python实现繁体中文与简体中文相互转换的方法示例
2018/12/18 Python
Python 脚本获取ES 存储容量的实例
2018/12/27 Python
SELENIUM自动化模拟键盘快捷键操作实现解析
2019/10/28 Python
Python 音频生成器的实现示例
2019/12/24 Python
Python GUI库PyQt5图形和特效样式QSS介绍
2020/02/25 Python
解决flask接口返回的内容中文乱码的问题
2020/04/03 Python
html5 postMessage解决跨域、跨窗口消息传递方案
2016/12/20 HTML / CSS
UGG雪地靴荷兰官网:UGG荷兰
2016/09/09 全球购物
英国灯具和灯泡网上商店:Lights.co.uk
2018/02/02 全球购物
意大利折扣和优惠券网站:Groupalia
2019/10/09 全球购物
品质主管的岗位职责
2013/12/04 职场文书
岳父生日宴会答谢词
2014/01/13 职场文书
小学生自我评价范文
2014/01/25 职场文书
生产助理岗位职责
2014/06/18 职场文书
在职员工证明书
2014/09/19 职场文书
2014年党员整改措施
2014/10/24 职场文书
起诉意见书范文
2015/05/19 职场文书
年终奖金发放管理制度,中小企业适用,拿去救急吧!
2019/07/12 职场文书
HTML5来实现本地文件读取和写入的实现方法
2021/05/25 HTML / CSS