RabbitMQ入门(三)订阅模式
在之前的文章RabbitMQ入门(二)工作队列中,我们创建了一个工作队列。工作队列背后的假设是每一项任务都被准确地传送至一个worker。在本文中,我们将会做一些不同的事情——我们将会把一个消息发送至许多消费者中。这种模式被称为订阅模式(publish/subscribe)。
为了解释这种模式,我们将会构建一个简单的日志系统。它包含两个程序——第一个将会产生消息,第二个将会接收并输出这些消息。
在我们的日志系统中,每一个正在运行的接收程序都会收到消息。在这种方式下,我们可以运行一个接收程序来接收并将日志保存至硬盘;同时,我们还能运行另一个接收程序,在屏幕上观察到日志的输出。
特别地,发送的这些消息都会被广播到所有的接收程序。
交换(Exchanges)
在之前的文章中,我们向队列发送消息,从队列中接受消息。现在是时候介绍RabbitMQ中的全部消息转发模式。
让我们快速地浏览下之前文章中讲了些什么:
- 一个生产者(Producer)是用于产生消息的用户应用程序;
- 一个队列(Queue)是缓存区,用于储存消息;
- 一个消费者(Consumer)是用于接收消息的用户应用程序。
RabbitMQ中消息传输模式的核心思想是生产者绝不会直接向队列发送任何消息。实际上,通常情况下生产者甚至都不会知道消息是否会被发送至队列。
生产者会将消息发送至交换(exchange)。交换并不复杂。一方面它从生产者中接受消息,另一方面将消息推送至队列。交换必须知道,当它接受一个消息时,它该怎么做。是否这个消息会附加至一个特殊的队列?是否它会附加至许多队列?或者它会被丢弃。这个规则用交换类型(exchange type)来定义。

有一些可用的交换类型:直接分发(direct),通配分发(topic),headers和复制分发(fanout)。我们将会集中讲最后一个——fanout。我们创建一个交换,类型为fanout,并取名为logs:
channel.exchange_declare(exchange='logs',
exchange_type='fanout')
fanout交换非常简单。顾名思义,它会将所有它知道的接收队列的消息都广播出去。而这也正是我们的日志系统所需要的。
现在,我们可以发布已经命名好的队列了:
channel.basic_publish(exchange='logs',
routing_key='',
body=message)
临时队列
你也许还记得在之前的文章中,我们需要给队列取名。但是呢,给队列命名太麻烦了——我们需要将workers指定到同一个队列。当你需要在生产者和消费者之间共享队列的时候,给队列命名又是很重要的。
这种情形并不适合我们的日志系统。我们想要监听所有的消息,而不是部分消息。同时,我们仅对当前的流动消息感兴趣,而不是之前的消息。为了解决这个问题,我们需要做两件事情。
首先,无论何时我们连接到RabbitMQ,我们需要一个新的空队列。为此,我们创建一个随机命名的队列,或者更好的是,让RabbitMQ Server来给我们创建一个随机命名的队列。因此,我们可以利用queue_declare命令,设置queuq参数为空:
result = channel.queue_declare(queue='')
此时,result.method.queue会包含一个随机命名的队列,比如说,它会和amq.gen-JzTY20BRgKO-HjmUJj0wLg类似。
其次,一旦消息者的连接关闭,我们需要删除队列。这可以用exclusive参数搞定:
result = channel.queue_declare(queue='', exclusive=True)
绑定(Bindings)

我们已经创建了一个fanout 交换和队列。现在我们需要告诉交换,将消息发送至队列。交换与队列之间的关系叫做绑定(Bindings)。
channel.queue_bind(exchange='logs',
queue=result.method.queue)
从现在开始,logs交换将会在我们的队列后追加消息。
代码

生产者代码(emit_log.py):
# -*- coding: utf-8 -*-
import pika
import sys
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
channel.exchange_declare(exchange='logs', exchange_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()
消费者代码(receive_log.py):
# -*- coding: utf-8 -*-
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
channel.exchange_declare(exchange='logs', exchange_type='fanout')
result = channel.queue_declare(queue='', 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(queue=queue_name, on_message_callback=callback, auto_ack=True)
channel.start_consuming()
开启四个终端,其中一个用于保存日志:
python3 receive_log.py > logs_from_rabbit.log
另一个用于观察日志输出:
python3 receive_log.py
日志产生:
python3 emit_log.py
监听绑定:
sudo rabbitmqctl list_bindings
运行截图如下:

本次分享到此结束,感谢大家阅读~
RabbitMQ入门(三)订阅模式的更多相关文章
- RabbitMQ入门-消息订阅模式
消息派发 上篇<RabbitMQ入门-消息派发那些事儿>发布之后,收了不少反馈,其中问的最多的还是有关消息确认以及超时等场景的处理. 楼主,有遇到消费者后台进程不在,但consumer连接 ...
- RabbitMQ入门-发布订阅模式
兔子的Publish/Subscribe是这样的: 有个生产者P,X代表交换机,交换机绑定队列,消费者从队列中取得消息.每次有消息,先发到交换机中,然后由交换机负责发送到它已知的队列中. 生产者代码: ...
- Rabbitmq交换机三种模式介绍
1.topic 将路由键和某模式进行匹配.此时队列需要绑定要一个模式上.符号“#”匹配一个或多个词,符号“*”匹配不多不少一个词.因此“abc.#”能够匹配到“abc.def.ghi”,但是“abc. ...
- RabbitMQ的发布订阅模式(Publish/Subscribe)
一.发布/订阅(Publish/Subscribe)模式 发布订阅是我们经常会用到的一种模式,生产者生产消息后,所有订阅者都可以收到.RabbitMQ的发布/订阅模型图如下: 1.该模式下生产者并不是 ...
- RabbitMQ简单应用の订阅模式
订阅模式 公众号-->订阅之后才会收到相应的文章. 解读: 1.一个生产者,多个消费者 2.每个消费者都有自己的队列 3.生产者没有将消息直接发送到队列里,而是发送给了交换机(转发器)excha ...
- RabbitMQ入门-竞争消费者模式
上一篇讲了个 哈喽World,现在来看看如果存在多个消费者的情况. 生产者: package com.example.demo; import com.rabbitmq.client.Channel; ...
- Java设计模式从精通到入门三 策略模式
介绍 我尽量用最少的语言解释总结: Java23种设计模式之一,属于行为型模式.一个类的行为或者算法可以在运行时更改,策略对象改变context对象执行算法. 应用实例: 以周瑜赔了夫人又折兵的例 ...
- RabbitMQ入门到进阶(Spring整合RabbitMQ&SpringBoot整合RabbitMQ)
1.MQ简介 MQ 全称为 Message Queue,是在消息的传输过程中保存消息的容器.多用于分布式系统 之间进行通信. 2.为什么要用 MQ 1.流量消峰 没使用MQ 使用了MQ 2.应用解耦 ...
- RabbitMQ入门案例
RabbitMQ入门案例 Rabbit 模式 https://www.rabbitmq.com/getstarted.html 实现步骤 构建一个 maven工程 导入 rabbitmq的依赖 启动 ...
随机推荐
- Linux 内核引用计数的操作
一个 kobject 的其中一个关键函数是作为一个引用计数器, 给一个它被嵌入的对象. 只 要对这个对象的引用存在, 这个对象( 和支持它的代码) 必须继续存在. 来操作一个 kobject 的引用计 ...
- vue面试的一些总结
vue中组件的data为什么是一个函数? 组件是可复用的vue实例,一个组件被创建好之后,就可能被用在各个地方,而组件不管被复用了多少次,组件中的data数据都应该是相互隔离,互不影响的,基于这一理念 ...
- 关于MySQL中查询大数据量的情况下分页limit的性能优化
https://blog.csdn.net/weixin_37848710/article/details/80772725
- JAVA兼职架构师
在一些小企业或者公司人力不足的时候,经常会出现一个人干多个人的活.开发可能会干架构.测试.运维,一些小项目可能需要一个人完成.我把这些角色合并在一起称之为兼职架构师. 我用我的经历来说说兼职架构师的需 ...
- Google老师亲授 TensorFlow2.0实战: 入门到进阶
Google老师亲授 TensorFlow2.0 入门到进阶 课程以Tensorflow2.0框架为主体,以图像分类.房价预测.文本分类等项目为依托,讲解Tensorflow框架的使用方法,同时学习到 ...
- pandas数据分析小知识点(一)
最近工作上,小爬经常需要用python做一些关于excel数据分析的事情,显然,从性能和拓展性的角度出发,使用pandas.numpy是比vba更好的选择.因为pandas能提供诸如SQL的很多查找. ...
- shellcode超级反杀
shellcode超级免杀 作者声明: 本文章属于作者原创,不能转载,违反网络安全法自己承担.这里只供学习使用. 日期: 2019-12-30 我试过了电脑管家,火绒安全,360....一系列杀毒软件 ...
- mysql主丛之基于binlog的不停业务配置主从
一 环境准备 主:192.168.132.121 从:192.168.132.122 主的数据库上面已经有数据,而且还在不断的写入 mysql> select * from darren.tes ...
- 洛谷$P4211\ [LNOI2014]\ LCA$ 树链剖分+线段树
正解:树剖+线段树 解题报告: 传送门$QwQ$ 看到$dep[lca]$啥的就想到之前托腮腮$CSP$模拟$D1T3$的那个套路,,, 然后试下这个想法,于是$dep[lca(x,y)]=\sum_ ...
- PrototypePattern(原型模式)-----Java/.Net
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式.