RabbitMQ之发布订阅
工作队列中,每个任务之分发给一个工作者。如果需要分发一个消息给多个消费者,这种模式被称为“发布/订阅”
交换器(Exchanges)
RabbitMQ完整的消息模型
发布者(producer)是发布消息的应用程序
队列(queue)用于消息存储的缓冲
消费者(consumer)是接收消息的应用程序
RabbitMQ消息模型的核心理念是:
发布者(producer)不会直接发送任何消息给队列。事实上,发布者(producer)甚至不知道消息是否已经被投递到队列。
发布者(producer)只需要把消息发送给一个交换器(exchage),然后由它一边从发布者接收消息,一边把消息推入队列。交换器必须知道如何处理它接收到的消息,是应该推送到指定的队列还是多个队列,或者直接忽略消息。这些规则通过exchange type来定义。

交换器类型
1、direct
处理路由键,需要将一个队列绑定到交换机上,要求该消息与一个特定的路由键完全匹配。
是完整的匹配,与routing_key对应。

2、topic
将路由键和某模式进行匹配。此时队列需要绑定在一个模式上。

3、headers
heads类型的Exchange不依赖于routing key与bingding key的匹配规则来路由消息,而是根据发送的消息内容中的headers属性进行匹配。
在绑定Queue与Exchange时指定一组键值对,当消息发送到Exchange时,RabbitMQ会取到该消息的headers,对比其中的键值对是否完全匹配Queue与Exchange绑定时指定的键值对,如果完全匹配,则消息路由到该队列,否则不会路由。

4、fanout
不处理路由键,只需要简单的将队列绑定到交换机上。一个发送到交换机的消息都会被转发到与该交换机绑定的所有队列上。类似子网广播,每台子网内的主机都获得一份复制的消息。
fanout交换机转发消息是最快的。

Exchange声明方法
exchange_declare(self, exchange=None, exchange_type='direct', passive=False, durable=False, auto_delete=False, internal=False, nowait=False, arguments=None, type=None) method of pika.adapters.blocking_connection.BlockingChannel instance
This method creates an exchange if it does not already exist, and if
the exchange exists, verifies that it is of the correct and expected
class. If passive set, the server will reply with Declare-Ok if the exchange
already exists with the same name, and raise an error if not and if the
exchange does not already exist, the server MUST raise a channel
exception with reply code 404 (not found). :param exchange: The exchange name consists of a non-empty sequence of
these characters: letters, digits, hyphen, underscore,
period, or colon.
:type exchange: str or unicode
:param str exchange_type: The exchange type to use
:param bool passive: Perform a declare or just check to see if it exists
:param bool durable: Survive a reboot of RabbitMQ
:param bool auto_delete: Remove when no more queues are bound to it
:param bool internal: Can only be published to by other exchanges
:param bool nowait: Do not expect an Exchange.DeclareOk response
:param dict arguments: Custom key/value pair arguments for the exchange
:param str type: The deprecated exchange type parameter
列出服务器上所有的交换器
guosong@guosong:~$ rabbitmqctl list_exchanges
Listing exchanges ...
direct
amq.direct direct
amq.fanout fanout
amq.headers headers
amq.match headers
amq.rabbitmq.log topic
amq.rabbitmq.trace topic
amq.topic topic
...done.
匿名的交换器
之前的列子中指定exchange=‘’,命名为空字符串。
channel.basic_publish(exchange='',
routing_key='hello',
body=message)
exchange参数就是交换器的名称,空字符串代表匿名交换器,消息将会根据指定的routing_key分发到指定的队列。
临时队列
对于共享同队列的需求,指定队列名称比较重要。
对于日志系统而言,打算接收所有的日志消息,关心的是最新的消息。
为了解决这个问题,需要做两件事情。
1、随机创建队列名
RabbitMQ可以为我们选择一个随机的队列名(推荐),当然也可以指定。
#通过不指定queue参数值,实现RabbitMQ分配随机队列名
result = channel.queue_declare() #可以通过如下方式获取消息队列名称
result.method.queue
2、当与消费者(consumer)断开连接的时候,这个队列应当被删除。可以使用exclusive标识。
result = channel.queue_declare(exclusive=True)
绑定(Bindings,队列与交换器之间绑定)

已经创建一个fanout类型的交换器和一个队列。需要告诉交换器如何发送消息给我们的队列。
交换器和队列之间的关系称之为绑定(binding)
#logs交换器将会把消息添加到队列中
#队列是上面说的服务器随机命名的
channel.queue_bind(exchange='logs',
queue=result.method.queue)
绑定列表查看
guosong@guosong:~$ rabbitmqctl list_bindings
Listing bindings ...
exchange task_queue queue task_queue []
gs_test_exchange exchange task_queue queue task_queue []
...done.
例子

把消息发送给logs交换器,在发送的时候提供routing_key参数,但是它的值会被fanout交换器忽略
#!/usr/bin/env python
#-*- coding:utf8 -*-
import sys
import pika
import logging logging.basicConfig(format='%(levelname)s:$(message)s',level=logging.CRITICAL) def emit_log(): pika.connection.Parameters.DEFAULT_HOST = 'localhost'
pika.connection.Parameters.DEFAULT_PORT = 5672
pika.connection.Parameters.DEFAULT_VIRTUAL_HOST = '/'
pika.connection.Parameters.DEFAULT_USERNAME = 'guosong'
pika.connection.Parameters.DEFAULT_PASSWORD = 'guosong' para = pika.connection.Parameters() connection = pika.BlockingConnection(para) channel = connection.channel()
#声明一个logs交换器,类型为fanout,不允许发布消息到不存在的交换器
channel.exchange_declare(exchange='logs',type='fanout') message = '.'.join(sys.argv[1:]) or "info:Hello World!" #发送的时候指定routing_key为空,没有绑定队列到交换器上,消息将会丢失
#对于日志类消息,如果没有消费者监听的话,这些消息就会忽略
channel.basic_publish(exchange='logs',routing_key='',body=message) #%r也是string类型
print "[x] Sent %r" % (message,) connection.close() if __name__ == '__main__':
emit_log()
演示结果
1、两个临时队列

2、两个consumer输出

第二个consumer开启晚一些,因此其收到消息少一些,因为在发布的时候指定routing_key为空,exchange不会保留。
3、在consumer退出的时候,两个临时产生的队列也自动删除。
logs交换器把数据发送给两个系统命名的队列,符合期望需求。
参考链接
1、http://zhanghua.1199.blog.163.com/blog/static/4644980720128732417654/
2、http://adamlu.net/rabbitmq/tutorial-three-python
3、http://blog.csdn.net/puncha/article/details/8449273
4、http://www.ostest.cn/archives/497
RabbitMQ之发布订阅的更多相关文章
- RabbitMQ之发布订阅【译】
在上一节中我们创建了一个工作队列,最好的情况是工作队列能够把任务恰到好处的分配给每一个worker.这一节中我们将做一些完全不同的事情--将消息传递给每一个消费者,这种模式被称为发布/订阅. 为了说明 ...
- RabbitMQ的发布订阅模式(Publish/Subscribe)
一.发布/订阅(Publish/Subscribe)模式 发布订阅是我们经常会用到的一种模式,生产者生产消息后,所有订阅者都可以收到.RabbitMQ的发布/订阅模型图如下: 1.该模式下生产者并不是 ...
- 【译】RabbitMQ:发布-订阅(Publish/Subscribe)
在前一篇教程中,我们创建了一个工作队列,我们假设在工作队列后的每一个任务都只被调度给一个消费者.在这一部分,我们将做一些完全不一样的事情,调度同一条消息给多个消费者,也就是有名的“发布-订阅”模式.为 ...
- RabbitMQ入门-发布订阅模式
兔子的Publish/Subscribe是这样的: 有个生产者P,X代表交换机,交换机绑定队列,消费者从队列中取得消息.每次有消息,先发到交换机中,然后由交换机负责发送到它已知的队列中. 生产者代码: ...
- 四.RabbitMQ之发布/订阅(Publish/Subscribe)
一.基础知识点 在上述章节中,我们理解的RabbitMQ是基于如下这种模式运作的. 而事实上,这只是我们简单化了的模型的结果,真正的模型应该是这样的. P:Producer 生产者,生产消息,把它放进 ...
- rabbitmq (三) 发布/订阅
rabbitmq的目的并不是让生产者把消息直接发到队列里面去, 这样不能实现解耦的目的,也不利于程序的扩展. 所以就有交换机(exchanges)的概念. 交换机有几种类型:direct, topic ...
- RabbitMQ 发布订阅
互联网公司对消息队列是深度使用者,因此需要我们了解消息队列的方方面面,良好的设计及深入的理解,更有利于我们对消息队列的规划. 当前我们使用消息队列中发现一些问题: 1.实际上是异步无返回远程调用,由发 ...
- RabbitMQ入门_08_所谓的点对点与发布订阅模型
A. JMS 模型 JMS 中定义了点对点和发布订阅两种消息模型,原来以为 AMQP 协议中 direct Exchange 对应点对点模型,topic Exchange 对应发布订阅模型,fanou ...
- rabbitmq消息队列——"发布订阅"
三."发布订阅" 上一节的练习中我们创建了一个工作队列.队列中的每条消息都会被发送至一个工作进程.这节,我们将做些完全不同的事情--我们将发送单个消息发送至多个消费者.这种模式就是 ...
随机推荐
- Silverlight:telerik RadControls for Silverlight 主题使用心得
默认情况下: telerik RadControls控件使用的是Office Black 主题,就算在App.xaml.cs里写上 StyleManager.ApplicationTheme = ne ...
- git subtree pull 错误 Working tree has modifications
git subtree 是不错的东西,用于 git 管理子项目. 本文记录我遇到问题和翻译网上的答案. 当我开始 pull 的时候,使用下面的代码 git subtree pull --prefix= ...
- mySQL:两表更新(用一个表更新另一个表)的SQL语句
用一个表中的字段去更新另外一个表中的字段, MySQL 中有相应的 update 语句来支持,不过这个 update 语法有些特殊.看一个例子就明白了. create table student ( ...
- 接口测试思路,jmeter,接口测试流程
接口测试总结 一:接口测试思想 接口测试:通过向服务器端发送请求,获取响应与预期结果做对比的一种服务端黑盒测试过程. 解释:接口就是将浏览器,客户端,手机端,或者服务器调用另一个服务器的请求抽离出来测 ...
- Windows下使用nginx搭建反向代理服务器
反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时 ...
- Java基础总结--流程控制
Java流程控制* 顺序结构--最常见的执行情况,语句按照出现的先后次序依次执行.* 判断结构--对条件进行判断,执行相应的语句.有三种常见的形式< if(判断条件){语句;}--为真执行语句, ...
- C++ 对象成员函数(非静态方法)
1.神奇的inline语法与语义 inline语义C99和C++98都有.之前在单源文件编写的时候一直没有发现问题,但是一考虑到多文件的链接,就发现矛盾了. 一些inline的原则: 1. inlin ...
- MQTT——连接报文
学习MQTT协议.如果只是看了相关文档就认为可以了.那是一个错误的观念.笔者为了能更好的去理解MQTT协议.看了不少相关的开源Broker的项目.可惜这些项目一般都是不完全的.不过从这些项目中笔者至少 ...
- java语言在某个数组中查找某个字符出现的次数
package com.llh.demo; import java.util.Scanner; /** * * @author llh * */ public class Test { /* * 在某 ...
- HDU1222Wolf and Rabbit(GCD思维)
Wolf and Rabbit Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)T ...