快速入门分布式消息队列之 RabbitMQ(3)
目录
前文列表
快速入门分布式消息队列之 RabbitMQ(1)
快速入门分布式消息队列之 RabbitMQ(2)
前言
在前文列表中,分别介绍了 RabbitMQ 的对象概念及其关键特性,本篇将通过编程的方式来回溯这些知识点,从实践应用的角度继续深入 RabbitMQ。
安装 RabbitMQ 的 Python 客户端 pika:
pip install pika
通道 Channel
在代码实现之前我们还需要补充一个通讯概念——通道
通道 channel:也被称为频道,指在 TCP 连接中建立的虚拟通信渠道。RabbitMQ 客户端与服务器之间的通讯并没有直接使用 TCP 连接,因为每一次通讯都需要创建和销毁 TCP 连接,这对操作系统来说是一笔昂贵的开销。并且 TCP 连接数量是有限制的,会成为通讯性能的瓶颈。解决该问题的方法就是在一个 TCP 连接中创建多个虚拟连接通道,而且通道的数量并没有限制,性能也很好。所以,通常我们只需要在应用程序中维护少量甚至一个 TCP 连接即可满足需求。
一个基本的生产者/消费者实现
消费者
import pika
# 消费者回调任务,在这里定义消费者处理消息数据的逻辑。
def consumer_callback(channel, method, properties, body):
print " [x] Consumed %r" % (body,)
# 定义 AMQP URL,这里使用前文中已经创建好的超级管理员 mickey 和虚拟主机 web_app
params = pika.URLParameters('amqp://mickey:passw0rd@localhost:5672/web_app')
# 创建与 RabbitMQ 的连接,也称为消息代理连接
conn = pika.BlockingConnection(params)
# 新建一个连接中的通道
channel = conn.channel()
# 声明一个直连交换机,通过消息路由键和绑定路由键的匹配来完成路由转发策略
# 参数 durable=True, auto_delete=False 表示希望持久化交换机
# 其中 durable=True 表示 RabbitMQ 重启后会自动重建该交换机
channel.exchange_declare(exchange='web', exchange_type='direct',
passive=False, durable=True, auto_delete=False)
# 声明一个队列,如果生产者将消息发送给了一个不存在的队列,那么 RabbitMQ 会自动丢弃该消息
channel.queue_declare(queue='app')
# 将队列绑定到交换机,并设置一个路由键
channel.queue_bind(queue='app',
exchange='web',
routing_key='web_app_route')
# 指定消费者订阅的队列,并且告诉消息代理不需要等待 ACK
channel.basic_consume(consumer_callback, queue='app', no_ack=True)
# 开始监听订阅队列,直到 CTRL+C 退出。
try:
print(" [*] Waiting for messages. To exit press CTRL+C")
channel.start_consuming()
except KeyboardInterrupt as err:
channel.stop_consuming()
conn.close()
生产者
import json
import pika
import sys
# 同样需要建立连接和通道
params = pika.URLParameters('amqp://mickey:passw0rd@localhost:5672/web_app')
conn = pika.BlockingConnection(params)
channel = conn.channel()
# 将在生产者中声明的 RabbitMQ 对象再重新声明一次,如果已经存在了则不会重复创建
# 这段逻辑实际上可有可无,只是为了说明声明一个 RabbitMQ 对象并不表示一定会创建
# 只有在第一次声明该对象的时候才会创建,之后无论在生成者或消费者中都可以再次声明
# channel.exchange_declare(exchange='web', exchange_type='direct',
# passive=False, durable=True, auto_delete=False)
# channel.queue_declare(queue='app')
# channel.queue_bind(queue='app',
# exchange='web',
# routing_key='web_app_route')
# 配置 AMQP 消息的 BasicProperties 基本属性
# 在 AMQP 协议中定义了 14 种 Properties,会随消息一同传递,这里表示使用 JSON 格式数据流
# 参数 delivery_mode=2 表示希望持久化消息,在 RabbitMQ 重启后自动重建消息
# 前文也提到过,持久化消息需要考虑到性能成本的问题
props = pika.BasicProperties(content_type='application/json', delivery_mode=2)
message = ' '.join(sys.argv[1:]) or "Hello World!"
body = {'msg': message}
# 发布消息,指定消息传递的交换机和所携带的路由键
print(" [x] Publish %s", message)
channel.basic_publish(exchange='web',
routing_key='web_app_route',
body=json.dumps(body),
properties=props)
conn.close()
NOTE:如果你希望使用缺省的虚拟主机和 guest 用户时,你的 AMQP URL 应该是这样的:
# '%2F' 是缺省虚拟主机 '/' 的转义
params = pika.URLParameters('amqp://guest:guest@localhost:5672/%2F')
运行结果
在两个终端分别运行生产者和消费者。
- 生产者
$ python producer.py First message.
(' [x] Publish %s', 'First message.')
$ python producer.py First message
(' [x] Publish %s', 'First message')
$ python producer.py Second message
(' [x] Publish %s', 'Second message')
$ python producer.py Third message
(' [x] Publish %s', 'Third message')
$ python producer.py
(' [x] Publish %s', 'Hello World!')
- 消费者
$ python consumer.py
[*] Waiting for messages. To exit press CTRL+C
[x] Consumed '{"msg": "First message"}'
[x] Consumed '{"msg": "Second message"}'
[x] Consumed '{"msg": "Third message"}'
[x] Consumed '{"msg": "Hello World!"}'
可以通过 CLI 来查看队列的消息情况:
$ rabbitmqctl list_queues -p web_app
Listing queues ...
app 0
...done.
NOTE:需要注意的是,上例中仅运行了一对生产者/消费者。实际上我们可以尝试同时运行多个消费者,并订阅到一个队列。这样的话,RabbitMQ 就会默认以分摊的方式将消息分别给多个消费者。
应用预取计数
我们知道,因为每个消费者执行的任务长度不尽相同,如果使用分摊的方式来分配消息的话,那么任务粒度小、执行时间短的消费者就会闲置下来。解决的方法就是在消费者中应用预期计数来实现公平调度(Fair dispatch)的效果。
# 当预取计数为 1 时,RabbitMQ 不会同时为消费者分配多个任务,只有等消费者处理完消息之后,才会接收下一个消息
channel.basic_qos(prefetch_count=1)
# 当预取计数为 10 时,RabbitMQ 会同时让消费者取出 10 个消息,直到 10 个消息都处理完之后,再继续接收下一次 10 个消息
# channel.basic_qos(prefetch_count=10)
可见,当消费者执行的任务长度较短时,应该给予更大的预取计数,来充当发挥消费者的性能。
应用 ACK 机制
应用 ACK 机制,来保证消息的有效传递。
def consumer_callback(channel, method, header_props, body):
print " [x] Consumed %r" % (body,)
# 在处理完消息之后,返回 ACK 消息应答
channel.basic_ack(delivery_tag=method.delivery_tag)
# 订阅队列的时候,参数 no_ack=False 表示告诉消息代理要等待 ACK 之后才将消息丢弃
channel.basic_consume(consumer_callback, queue='app', no_ack=False)
最后
如果你常接触 RabbitMQ,那么建议你结合上篇和中篇里提到的对象概念以及特性来浏览代码,相信会有更深的感触。除此之外,我们还可以在 RabbitMQ Tutorials 中获取更多的 Samples。
快速入门分布式消息队列之 RabbitMQ(3)的更多相关文章
- 快速入门分布式消息队列之 RabbitMQ(2)
目录 目录 前文列表 RabbitMQ 的特性 Message Acknowledgment 消息应答 Prefetch Count 预取数 RPC 远程过程调用 vhost 虚拟主机 插件系统 最后 ...
- 快速入门分布式消息队列之 RabbitMQ(1)
目录 目录 前言 简介 安装 RabbitMQ 基本对象概念 Message 消息 Producer 生产者 Consumer 消费者 Queue 队列 Exchange 交换机 Binding 绑定 ...
- 【转】快速理解Kafka分布式消息队列框架
from:http://blog.csdn.net/colorant/article/details/12081909 快速理解Kafka分布式消息队列框架 标签: kafkamessage que ...
- 分布式消息队列XXL-MQ
<分布式消息队列XXL-MQ> 一.简介 1.1 概述 XXL-MQ是一款轻量级分布式消息队列,支持串行.并行和广播等多种消息模型.现已开放源代码,开箱即用. 支持三种消息模式: ...
- RabbitMQ,Apache的ActiveMQ,阿里RocketMQ,Kafka,ZeroMQ,MetaMQ,Redis也可实现消息队列,RabbitMQ的应用场景以及基本原理介绍,RabbitMQ基础知识详解,RabbitMQ布曙
消息队列及常见消息队列介绍 2017-10-10 09:35操作系统/客户端/人脸识别 一.消息队列(MQ)概述 消息队列(Message Queue),是分布式系统中重要的组件,其通用的使用场景可以 ...
- Netty构建分布式消息队列(AvatarMQ)设计指南之架构篇
目前业界流行的分布式消息队列系统(或者可以叫做消息中间件)种类繁多,比如,基于Erlang的RabbitMQ.基于Java的ActiveMQ/Apache Kafka.基于C/C++的ZeroMQ等等 ...
- EQueue - 一个C#写的开源分布式消息队列的总体介绍
前言 本文想介绍一下前段时间在写enode时,顺便实现的一个分布式消息队列equeue.这个消息队列的思想不是我想出来的,而是通过学习阿里的rocketmq后,自己用c#实现了一个轻量级的简单版本.一 ...
- 分享一个c#写的开源分布式消息队列equeue
分享一个c#写的开源分布式消息队列equeue 前言 equeue消息队列中的专业术语 Topic Queue Producer Consumer Consumer Group Broker 集群消费 ...
- 消息队列之 RabbitMQ
https://www.jianshu.com/p/79ca08116d57 关于消息队列,从前年开始断断续续看了些资料,想写很久了,但一直没腾出空,近来分别碰到几个朋友聊这块的技术选型,是时候把这块 ...
随机推荐
- 现身说法:面对DDoS攻击时该如何防御?
上周,我们的网站遭到了一次DDoS攻击.虽然我对DDoS的防御还是比较了解,但是真正遇到时依然打了我个措手不及.DDoS防御是一件比较繁琐的事,面对各种不同类型的攻击,防御方式也不尽相同.对于攻击来的 ...
- Python 列表元素里面含有字典或者列表进行排序
示例1:列表里面含有列表进行排序 s = [[1, 2], [100, 2], [33, 3], [25, 6]] s.sort(key=lambda k: k[0]) print(s) 结果: [[ ...
- Delphi 变量
- 基于zynq XC7Z100 FMC接口通用计算平台 XC7Z100
一.板卡概述 本板卡基于Xilinx公司的FPGA XC7Z100 FFG 9000 芯片, 该平台为设计和验证应用程序提供了一个完整的开发平台.该平台使设计师能够更加简单进行高性能的原型设计,并 ...
- SpringBootMybatis02 mybatis-generator-gui|pageHelper|前后端分离|Filter权限实现
一.Mybatis-generator-gui 下载地址:https://github.com/LittlePageProgram/mybatis-generator-gui.git 使用方法:填写相 ...
- GlobalLock锁定一个全局内存对象
GlobalLock BAIPro
- 新建ext4分区及开机挂载
1.查看新的20G硬盘是否已经挂在完毕. 2.使用fdisk命令创建主分区 3.再将分区设置完毕之后,查看磁盘分区是否创建完成. 2.使用mkfs.ext4命令将新创建的分区进行格式化为: 1)blo ...
- DevExpress WPF v19.1新版亮点:Scheduler等控件新功能
行业领先的.NET界面控件DevExpress 日前正式发布v19.1版本,本站将以连载的形式介绍各版本新增内容.在本系列文章中将为大家介绍DevExpress WPF v19.1中新增的一些控件及部 ...
- Levenberg-Marquardt优化和zipf分布
最近审论文和看报告中遇到LM优化和齐普夫分布,于是查了一下. LM方法是高斯牛顿迭代方法的改进,下面分别是高斯牛顿.齐普夫方法的公式: Δ=−(JfTJf)−1JfTf,Δ=−(JfTJf+λI)−1 ...
- PIXI兼容微信小游戏
首先导入官方的weapp-adapter,然后导入pixi.min.js,微信小程序使用ES6的module引用模块,具体参见ES6的Module. import './libs/weapp-adap ...