关闭

基于Python语言使用RabbitMQ消息队列(三)

标签: 消息队列rabbitmq-实战Python
841人阅读 评论(0) 收藏 举报
分类:

发布/订阅

前面的教程中我们已经创建了一个工作队列。在一个工作队列背后的假设是每个任务恰好会传递给一个工人。在这一部分里我们会做一些完全不同的东西——我们会发送消息给多个消费者。这就是所谓的“发布/订阅”模式。

为了解释这种模式,我们将会构建一个简单的日志系统。它包含两个程序——第一个产生日志消息,第二个接收并把他们打印出来。

在我们的日志系统中,每一个接收程序的正在运行的拷贝都会获知消息,那样我们将能够运行一个接收者把日志指向磁盘;同时我们将能够运行另一个接收者在屏幕上查看日志。

实质上,被发布的消息将会广播给所有接收。

交易所

在前面的教程中我们向一个队列中发送和接收消息. 现在来介绍Rabbit中的完整的消息模型 .

我们快速回顾一下前面的教程:

  • 生产者是一个发送消息的用户应用。
  • 队列是一个存储消息的缓冲区。
  • 消费者是一个接收消息的用户应用。

RabbitMQ中消息模型的核心思想是,生产者从不直接发送任何消息给一个队列。实际上,生产者通常甚至一点都不知道一条消息会被发送给什么队列。
相反,生产者只能发送消息给一个交易所(exchange)。交易所是一个很简单的东西。它一面接收来自生产者的消息,一面把消息推送给队列。交易所必须准确知道如何对待它接收到的消息。它该被追加到一个特定队列中吗?还是应该把它追加到多个队列?又或者它该被忽略?这些规则都是由交易类型(exchange type)所定义的。
这里写图片描述
有几种可用的交易类型: direct, topic, headers 和 fanout. 我们会关注最后一个——fanout. 我们来创建一个这种类型的交易所,命名为 logs:

channel.exchange_declare(exchange='logs',
                         type='fanout')

fanout类型交易所非常简单。从名字中你可能已经猜到(其实英语非母语的也不大好猜到,fan(风扇)+out(外、出)的组合,我觉得在这里可以理解为扇出去、扬出去的意思),它只是广播它接到的所有消息给它知道的所有队列 ,这恰恰是我们的日志程序所需要的。

列出所有交际所

为了列出所有交易所,你可以运行Trabbitmqctl:

sudo rabbitmqctl list_exchanges 在这个列表中会有些像amq.* 的交易所和默认的(未命名的)交易所
这些是被默认创建的,但你目前不太可能需要用到它们。

默认交易所

在之前的教程中我们队交易所一无所知。但仍然能够给队列发送消息。这是因为我们使用了默认交易所,我们通过空字符串 (“”)来标识。

回顾一下我们之前如何发布一条消息:

channel.basic_publish(exchange='',
routing_key='hello',
body=message)

exchange 参数就是交易所的名字。空字符串代表默认或者无名交易所:
消息路由到名字被routing_key所指定的队列,如果队列存在的话。

现在我们可以把消息发布到命名交易所了:

channel.basic_publish(exchange='logs',
                      routing_key='',
                      body=message)

临时队列

你可能记得我们先前使用了有特定名字的队列 (记得 hello 和 task_queue?)。能给队列命名对我们来说很关键——我们需要把工人们指向同一个队列。当你想要在生产者和消费者中分享队列时,给队列一个名字就很重要。

但那不符合我们的日志程序需要。我们想获取所有日志消息,不只是他们的一个子集。我们也仅对当前活跃的消息感兴趣,而不是旧有的,解决这个问题我们需要做两件事。

第一,无论何时连接到Rabbit我们都需要一个新鲜的(fresh)空的(empty)队列 ,为实现这一点我们使用随机的名字创建一个队列,或者更好的——让服务器随机选一个队列名给我们。 我们不给queue_declare提供队列参数就可以做到:

result = channel.queue_declare()

这样的话, result.method.queue 就会包含一个任意的队列名,例如它可能看上去是这样的 : amq.gen-JzTY20BRgKO-HjmUJj0wLg.

第二, 一旦我们断开消费者链接,队列就该被删除掉。通过一个exclusive 标志实现:

result = channel.queue_declare(exclusive=True)

绑定

这里写图片描述
我们已经创建了一个fanout 交易所和一个队列。现在我们要通知交易所发送消息给我们的队列。交易所和一个队列之间的关系叫做绑定。

channel.queue_bind(exchange='logs',
                   queue=result.method.queue)

从现在开始logs交易所会追加消息给我们的队列。

列出所有绑定

你可以列出所有存在的绑定,使用…好吧,你已经猜到了:
rabbitmqctl list_bindings

整合

这里写图片描述
用来发送日志消息的生产者程序,看起来和之前并没有多大不同。最大的变化是我们现在想要发送消息给logs交易所而不是无名交易所。当发送时我们需要提供一个routing_key,但对于fanout类型交易所来说它的值是被忽略的。 下面是emit_log.py 脚本代码:

#!/usr/bin/env python
import pika
import sys

connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()

channel.exchange_declare(exchange='logs',
                         type='fanout')

message = ' '.join(sys.argv[1:]) or "info: Hello World!"
channel.basic_publish(exchange='logs',
                      routing_key='',
                      body=message)
print(" [x] Sent %r" % message)
connection.close()

如你所见,建立完连接后我们生命了交易所。这一步是必须的,因为发布到一个不存在的交易所是被禁止的。

如果没有队列连接(bound)到交易所,消息就会丢失,但对我们来说没有关系;如果没有消费者监听我们可以安全地忽略掉这个消息。

receive_logs.py代码:

#!/usr/bin/env python
import pika

connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()

channel.exchange_declare(exchange='logs',
                         type='fanout')

result = channel.queue_declare(exclusive=True)
queue_name = result.method.queue

channel.queue_bind(exchange='logs',
                   queue=queue_name)

print(' [*] Waiting for logs. To exit press CTRL+C')

def callback(ch, method, properties, body):
    print(" [x] %r" % body)

channel.basic_consume(callback,
                      queue=queue_name,
                      no_ack=True)

channel.start_consuming()

大功告成!如果你想把日志保存到一个文件中只需要打开控制台,键入:

python receive_logs.py > logs_from_rabbit.log

如果你想在屏幕查看日志, 打开一个新的控制台运行:

python receive_logs.py

下两图分别为在我的Ubuntu终端使用cat命令输出的存入到日志文件的日志和屏幕显示的日志
图1
1
图2
这里写图片描述
当然需要运行emit_log.py
这里写图片描述
使用 rabbitmqctl list_bindings 你可以确认代码创建了绑定和队列,就像我们想要的那样。在两个运行的情况下你应该会看到如下内容:

sudo rabbitmqctl list_bindings
# => Listing bindings ...
# => logs    exchange        amq.gen-JzTY20BRgKO-HjmUJj0wLg  queue           []
# => logs    exchange        amq.gen-vso0PVvyiRIL2WoV3i48Yg  queue           []
# => ...done.

结果的解释很直白: 来自logs交易所的数据去往两个服务器指定了名字的队列 ,这正是我们所预想的。
若想知道如何监听消息子集,请前往下一节。

0
0
查看评论

Python 学习入门(29)—— 消息队列

nakeMQ是一个跨平台的Python消息队列库。消息队列让不同主机间通信变得简单可靠。使用snakeMQ,只需要发送消息,剩下的事都交给snakeMQ处理。特色:纯python实现,跨平台自动重连接可靠发送--可配置的消息方式与消息超时方式持久化/临时 两种队列支持异步 -- poll()symm...
  • sunboy_2050
  • sunboy_2050
  • 2013-12-21 19:18
  • 10819

Python中的多线程threading和线程间消息队列queue学习笔记

python中实现多线程可以通过threading类。线程间同步则可以用queue类。至于python的进程间通信,暂时没有发现有类似linux ipc的模块可供使用,但是可以通过unix域套接字实现进程间通信。 1、用threading模块实现多线程     可以通过派生t...
  • l1902090
  • l1902090
  • 2014-04-30 17:15
  • 10217

python(十一)上:RabbitMQ 使用详细介绍

目录上节回顾 一、RabbitMQ 消息队列介绍 二、RabbitMQ基本示例.   1、Rabbitmq 安装   2、基本示例   3、RabbitMQ 消息分发轮询 三、RabbitMQ 消息持久化(durable、properties)   1、RabbitMQ 相关命令  ...
  • fgf00
  • fgf00
  • 2016-10-20 15:03
  • 11109

python系列之 RabbitMQ - RPC

远程过程调用(Remote procedure call (RPC)) 在第二课我们学习了怎样使用 工作队列(work queues) 来在多个workers之间分发需要消时的 任务 但是如果我们需要在远程的服务器上调用一个函数并获取返回结果 我们需要怎么做呢?well这是一个不一样的故事。 这中模...
  • songfreeman
  • songfreeman
  • 2016-03-22 00:22
  • 2319

史上最快python 异步消息队列zeromq 简介

zeromq是一个基于内存的消息队列 是一个有着青春和朝气的项目,可惜网站被和谐了 高吞吐,低延时,超乎你的想象. ØMQ is already very fast. We're getting 13.4 microseconds end-to-end latenci...
  • cometo985
  • cometo985
  • 2016-04-29 12:01
  • 742

在python下比celery更加简单的异步任务队列RQ

廖雪峰 / 编程 / 2013-8-27 19:33 / 阅读: 21 Celery是Python开发的分布式任务调度模块,今天抽空看了一下,果然接口简单,开发容易,5分钟就写出了一个异步发送邮件的服务。 Celery本身不含消息服务,它使用第三方消息服务来传递任务,目前,Celery支持的...
  • chenlei_525
  • chenlei_525
  • 2015-05-11 12:56
  • 3932

RabbitMQ(python实现)学习之二:Producer发送消息至多个消息队列queue(广播消息)

1.1本部分内容简介 这部分我们将要发送一个消息到多个Consumer,这部分称之为“publish/subscribe” 我们实现的方式就是发送端,发送一个消息,与此同时,多个接收端将同时接收到消息并打印在屏幕上面。 1.2exchange简介 在前面的博文中,我们的讲解是...
  • likai_liche
  • likai_liche
  • 2015-05-21 11:35
  • 1869

用 Flask 来写个轻博客 (26) — 使用 Flask-Celery-Helper 实现异步任务

目录目录 前文列表 扩展阅读 Celery 将 Celery 加入到应用中 实现向新用户发送欢迎邮件 前文列表用 Flask 来写个轻博客 (1) — 创建项目 用 Flask 来写个轻博客 (2) — Hello World! 用 Flask 来写个轻博客 (3) — (M)VC_连接 MyS...
  • Jmilk
  • Jmilk
  • 2016-12-15 21:48
  • 4940

kombu------python的消息库

kombu是一个python的消息库。 Kombu的目标是通过为AMQP协议提供一个地道的高层次接口,来使python中的消息编程更为简单。同时也为通用的消息问题提供试验和测试的解决方案。 AMQP是先进的消息队列协议,一个提供消息定位,队列,路由,高靠性和安全性的开放的标准协议,其中R...
  • happyAnger6
  • happyAnger6
  • 2016-05-17 23:12
  • 2631

基于Python语言使用RabbitMQ消息队列(三)

发布/订阅前面的教程中我们已经创建了一个工作队列。在一个工作队列背后的假设是每个任务恰好会传递给一个工人。在这一部分里我们会做一些完全不同的东西——我们会发送消息给多个消费者。这就是所谓的“发布/订阅”模式。为了解释这种模式,我们将会构建一个简单的日志系统。它包含两个程序——第一个产生日志消息,第二...
  • zhangfh1990
  • zhangfh1990
  • 2017-05-25 17:54
  • 841
    个人资料
    • 访问:9438次
    • 积分:358
    • 等级:
    • 排名:千里之外
    • 原创:13篇
    • 转载:5篇
    • 译文:14篇
    • 评论:3条