利用Python操作消息队列RabbitMQ的方法教程


Posted in Python onJuly 19, 2017

前言

RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统。他遵循Mozilla Public License开源协议。
MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们。消 息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用的技术。排队指的是应用程序通过 队列来通信。队列的使用除去了接收和发送应用程序同时执行的要求。

应用场景:

RabbitMQ无疑是目前最流行的消息队列之一,对各种语言环境的支持也很丰富,作为一个.NET developer有必要学习和了解这一工具。消息队列的使用场景大概有3种:

     1、系统集成,分布式系统的设计。各种子系统通过消息来对接,这种解决方案也逐步发展成一种架构风格,即“通过消息传递的架构”。

     2、当系统中的同步处理方式严重影响了吞吐量,比如日志记录。假如需要记录系统中所有的用户行为日志,如果通过同步的方式记录日志势必会影响系统的响应速度,当我们将日志消息发送到消息队列,记录日志的子系统就会通过异步的方式去消费日志消息。

     3、系统的高可用性,比如电商的秒杀场景。当某一时刻应用服务器或数据库服务器收到大量请求,将会出现系统宕机。如果能够将请求转发到消息队列,再由服务器去消费这些消息将会使得请求变得平稳,提高系统的可用性。

一、安装环境

首先是在 Linux 上安装 rabbitmq

# 环境为CentOS 7
yum install rabbitmq-server # 安装RabbitMQ
systemctl start rabbitmq-server # 启动
systemctl enable rabbitmq-server # 开机自启
systemctl stop firewall-cmd  # 临时关闭防火墙

然后用 pip 安装 Python3 的开发包

pip3 install pika

安装好软件之后可以访问http://115.xx.xx.xx:15672/来访问自带的 web 页面来查看和管理 RabbitMQ。默认管理员的用户密码都是guest

二、简单的向队列中加入消息

#!/usr/bin/env python3
# coding=utf-8
# @Time : 2017/6/13 19:25
# @Author : Shawn
# @Blog : https://blog.just666.cn
# @Email : shawnbluce@gmail.com
# @purpose : RabbitMQ_Producer
import pika
# 创建连接对象
connection = pika.BlockingConnection(pika.ConnectionParameters(host='115.xx.xx.xx'))
# 创建频道对象
channel = connection.channel()
# 指定一个队列,如果该队列不存在则创建
channel.queue_declare(queue='test_queue')
# 提交消息
for i in range(10):
 channel.basic_publish(exchange='', routing_key='test_queue', body='hello,world' + str(i))
 print("sent...")
# 关闭连接
connection.close()

三、简单的从队列中获取消息

#!/usr/bin/env python3
# coding=utf-8
# @Time : 2017/6/13 19:40
# @Author : Shawn
# @Blog : https://blog.just666.cn
# @Email : shawnbluce@gmail.com
# @purpose : RabbitMQ_Consumer
import pika
credentials = pika.PlainCredentials('guest', 'guest')
# 连接到RabbitMQ服务器
connection = pika.BlockingConnection(pika.ConnectionParameters('115.xx.xx.xx', 5672, '/', credentials))
channel = connection.channel()
# 指定一个队列,如果该队列不存在则创建
channel.queue_declare(queue='test_queue')
# 定义一个回调函数
def callback(ch, method, properties, body):
 print(body.decode('utf-8'))
# 告诉RabbitMQ使用callback来接收信息
channel.basic_consume(callback, queue='test_queue', no_ack=False)
print('waiting...')
# 开始接收信息,并进入阻塞状态,队列里有信息才会调用callback进行处理。按ctrl+c退出。
channel.start_consuming()

四、万一消费者掉线了

想象这样一种情况:

消费者从消息队列中获取了 n 条数据,正要处理呢结果宕机了,那该怎么办?在 RabbieMQ 中有一个 ACK 可以用来确认消费者处理结束。就有点类似网络中的 ACK,消费者每次从队列中获取了数据之后队列不会立刻将数据移除,而是等待对应的 ACK。消费者获取到数据并处理完成之后会向队列发送一个 ACK 包,通知 RabbitMQ 这堆消息已经处理妥当了,可以删除了,这时候 RabbitMQ 才会将数据从队列中移除。所以这种情况下即使消费者掉线也没有什么问题,数据依旧会在队列中存在,留给其他消费者处理。

在 Python 中这样实现:

消费者有这样一行代码channel.basic_consume(callback, queue='test_queue', no_ack=False) ,其中no_ack=False表示不发送确认包。将其修改为no_ack=True就会在每次处理完之后向 RabbitMQ 发送一个确认包,以确认消息处理完毕。

五、万一 RabbitMQ 宕机了呢

虽然有了 ACK 包,但是万一 RabbitMQ 挂了那数据还是会损失。所以我们可以给 RabbitMQ 设置一个数据持久化存储。RabbitMQ 会将数据持久化存储到磁盘上,保证下次再启动的时候队列还在。

在 Python 中这样实现:

我们声明一个队列是这样的channel.queue_declare(queue='test_queue') ,如果需要持久化一个队列可以这样声明channel.queue_declare(queue='test_queue', durable=True) 。不过这行直接放在代码中是不能执行的,因为以前已经有了一个名为test_queue的队列,RabbitMQ 不允许用不同的方式声明同一个队列,所以可以换一个队列名新建来指定数据持久化存储。不过如果只是这样声明的话,在 RabbitMQ 宕机重启后确实队列还在,不过队列里的数据就没有了。除非我们这样来声明队列channel.basic_publish(exchange='', routing_key="test_queue", body=message, properties=pika.BasicProperties(delivery_mode = 2,))

六、最简单的发布订阅

最简单的发布订阅在 RabbitMQ 中称之为Fanout模式。也就是说订阅者订阅某个频道,然后发布者向这个频道中发布消息,所有订阅者就都能接收到这条消息。不过因为发布者需要使用订阅者创建的随机队列所以需要先启动订阅者才能启动发布者。

发布者代码:

#!/usr/bin/env python3
# coding=utf-8
# @Time : 2017/6/13 20:21
# @Author : Shawn
# @Blog : https://blog.just666.cn
# @Email : shawnbluce@gmail.com
# @purpose : RabbitMQ_Publisher
import pika
# 创建连接对象
connection = pika.BlockingConnection(pika.ConnectionParameters(host='115.xx.xx.xx'))
# 创建频道对象
channel = connection.channel()
# 定义交换机,exchange表示交换机名称,type表示类型
channel.exchange_declare(exchange='my_fanout',
       type='fanout')
message = 'Hello Python'
# 将消息发送到交换机
channel.basic_publish(exchange='my_fanout', # 指定exchange
      routing_key='', # fanout下不需要配置,配置了也不会生效
      body=message)
connection.close()

订阅者代码:

#!/usr/bin/env python3
# coding=utf-8
# @Time : 2017/6/13 20:20
# @Author : Shawn
# @Blog : https://blog.just666.cn
# @Email : shawnbluce@gmail.com
# @purpose : RabbitMQ_Subscriber
import pika
credentials = pika.PlainCredentials('guest', 'guest')
# 连接到RabbitMQ
connection = pika.BlockingConnection(pika.ConnectionParameters('115.xx.xx.xx', 5672, '/', credentials))
channel = connection.channel()
# 定义交换机,进行exchange声明,exchange表示交换机名称,type表示类型
channel.exchange_declare(exchange='my_fanout',
       type='fanout')
# 随机创建队列
result = channel.queue_declare(exclusive=True) # exclusive=True表示建立临时队列,当consumer关闭后,该队列就会被删除
queue_name = result.method.queue
# 将队列与exchange进行绑定
channel.queue_bind(exchange='my_fanout',
     queue=queue_name)
# 定义回调方法
def callback(ch, method, properties, body):
 print(body.decode('utf-8'))
# 从队列获取信息
channel.basic_consume(callback,
      queue=queue_name,
      no_ack=True)
channel.start_consuming()

总结

以上就是这篇文章的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
Python中的列表知识点汇总
Apr 14 Python
Python中Threading用法详解
Dec 27 Python
在Python文件中指定Python解释器的方法
Feb 18 Python
python禁用键鼠与提权代码实例
Aug 16 Python
Python Django 封装分页成通用的模块详解
Aug 21 Python
python绘制雪景图
Dec 16 Python
Python-numpy实现灰度图像的分块和合并方式
Jan 09 Python
Python3中的f-Strings增强版字符串格式化方法
Mar 04 Python
python GUI库图形界面开发之PyQt5动态(可拖动控件大小)布局控件QSplitter详细使用方法与实例
Mar 06 Python
基于python实现上传文件到OSS代码实例
May 09 Python
解决pip install psycopg2出错问题
Jul 09 Python
一文详述 Python 中的 property 语法
Sep 01 Python
高效测试用例组织算法pairwise之Python实现方法
Jul 19 #Python
Python实现将文本生成二维码的方法示例
Jul 18 #Python
Python实现动态加载模块、类、函数的方法分析
Jul 18 #Python
Python使用plotly绘制数据图表的方法
Jul 18 #Python
python中日志logging模块的性能及多进程详解
Jul 18 #Python
浅谈python中的__init__、__new__和__call__方法
Jul 18 #Python
Pycharm编辑器技巧之自动导入模块详解
Jul 18 #Python
You might like
php mysql数据库操作分页类
2008/06/04 PHP
phpmailer发送邮件之后,返回收件人是否阅读了邮件的方法
2014/07/19 PHP
服务器上配置PHP运行环境教程
2015/02/12 PHP
那些年,我还在学习jquery 学习笔记
2012/03/05 Javascript
使用javascript创建快捷方式的简单实例
2013/08/09 Javascript
Jquery ajax执行顺序 返回自定义错误信息(实例讲解)
2013/11/06 Javascript
js 调用百度地图api并在地图上进行打点添加标注
2014/05/13 Javascript
Javascript刷新页面的实例
2017/09/23 Javascript
利用ES6实现单例模式及其应用详解
2017/12/09 Javascript
理解Koa2中的async&await的用法
2018/02/05 Javascript
Bootstrap 中data-[*] 属性的整理
2018/03/13 Javascript
使用Angular自定义字段校验指令的方法示例
2019/02/01 Javascript
vue中使用vue-cli接入融云实现即时通信
2019/04/19 Javascript
JS自定义对象创建与简单使用方法示例
2020/01/15 Javascript
微信小程序修改checkbox的样式代码实例
2020/01/21 Javascript
js实现无缝轮播图插件封装
2020/07/31 Javascript
Python模拟鼠标点击实现方法(将通过实例自动化模拟在360浏览器中自动搜索python)
2017/08/23 Python
Python实现识别手写数字大纲
2018/01/29 Python
Python中的单继承与多继承实例分析
2018/05/10 Python
Python面向对象程序设计之继承与多继承用法分析
2018/07/13 Python
深入理解Django自定义信号(signals)
2018/10/15 Python
python3实现名片管理系统
2020/11/29 Python
Python利用字典破解WIFI密码的方法
2019/02/27 Python
Python Django简单实现session登录注销过程详解
2019/08/06 Python
python保存log日志,实现用log日志画图
2019/12/24 Python
关于python 跨域处理方式详解
2020/03/28 Python
详解Anaconda 的安装教程
2020/09/23 Python
selenium与xpath之获取指定位置的元素的实现
2021/01/26 Python
斯洛伐克香水和化妆品购物网站:Parfemy-Elnino.sk
2020/01/28 全球购物
雷朋巴西官方商店:Ray-Ban Brasil
2020/07/21 全球购物
建筑设计师岗位职责
2013/11/18 职场文书
网络研修随笔感言
2014/02/17 职场文书
奥巴马连任演讲稿
2014/05/15 职场文书
刑事上诉状范文
2015/05/22 职场文书
欠条范文
2015/07/03 职场文书
Redis入门教程详解
2021/08/30 Redis