RabbitMQ 使用主题进行消息分发
在上篇文章RabbitMQ消息队列(五):Routing 消息路由 中,我们实现了一个简单的日志系统。Consumer可以监听不同severity的log。但是,这也是它之所以叫做简单日志系统的原因,因为是仅仅能够通过severity设定。不支持更多的标准。
比如syslog unix的日志工具,它可以通过severity (info/warn/crit...) 和模块(auth/cron/kern...)。这可能更是我们想要的:我们可以仅仅需要cron模块的log。
为了实现类似的功能,我们需要用到topic exchange。
1. Topic exchange
对于Message的routing_key是有限制的,不能使任意的。格式是以点号“."分割的字符表。比如:"stock.usd.nyse", "nyse.vmw", "quick.orange.rabbit"。你可以放任意的key在routing_key中,当然最长不能超过255 bytes。
对于routing_key,有两个特殊字符(在正则表达式里叫元字符):
- * (星号) 代表任意 一个单词
- # (hash) 0个或者多个单词
请看下面一个例子:

Producer发送消息时需要设置routing_key,routing_key包含三个单词和两个点号。第一个key是描述了celerity(灵巧,敏捷),第二个是colour(色彩),第三个是species(物种):"<celerity>.<colour>.<species>"。
在这里我们创建了两个绑定: Q1 的binding key 是"*.orange.*"; Q2 是 "*.*.rabbit" 和 "lazy.#":
- Q1 感兴趣所有orange颜色的动物
- Q2 感兴趣所有的rabbits和所有的lazy的
比如routing_key是 "quick.orange.rabbit"将会发送到Q1和Q2中。消息"lazy.orange.elephant" 也会发送到Q1和Q2。但是"quick.orange.fox" 会发送到Q1;"lazy.brown.fox"会发送到Q2。"lazy.pink.rabbit" 也会发送到Q2,但是尽管两个routing_key都匹配,它也只是发送一次。"quick.brown.fox" 会被丢弃。
如果发送的单词不是3个呢? 答案要看情况,因为#是可以匹配0个或任意个单词。比如"orange" or "quick.orange.male.rabbit",它们会被丢弃。如果是lazy那么就会进入Q2。类似的还有 "lazy.orange.male.rabbit",尽管它包含四个单词。
Topic exchange和其他exchange
由于有"*" (star) and "#" (hash), Topic exchange 非常强大并且可以转化为其他的exchange:
如果binding_key 是 "#" - 它会接收所有的Message,不管routing_key是什么,就像是fanout exchange。
如果 "*" (star) and "#" (hash) 没有被使用,那么topic exchange就变成了direct exchange。
2. 代码实现
现在我们要refine我们上篇的日志系统。routing keys 有两个部分: "<facility>.<severity>"。
The code for emit_log_topic.py:
- #!/usr/bin/env python
- import pika
- import sys
- connection = pika.BlockingConnection(pika.ConnectionParameters(
- host='localhost'))
- channel = connection.channel()
- channel.exchange_declare(exchange='topic_logs',
- type='topic')
- routing_key = sys.argv[1] if len(sys.argv) > 1 else 'anonymous.info'
- message = ' '.join(sys.argv[2:]) or 'Hello World!'
- channel.basic_publish(exchange='topic_logs',
- routing_key=routing_key,
- body=message)
- print " [x] Sent %r:%r" % (routing_key, message)
- connection.close()
#!/usr/bin/env python
import pika
import sys connection = pika.BlockingConnection(pika.ConnectionParameters(
host='localhost'))
channel = connection.channel() channel.exchange_declare(exchange='topic_logs',
type='topic') routing_key = sys.argv[1] if len(sys.argv) > 1 else 'anonymous.info'
message = ' '.join(sys.argv[2:]) or 'Hello World!'
channel.basic_publish(exchange='topic_logs',
routing_key=routing_key,
body=message)
print " [x] Sent %r:%r" % (routing_key, message)
connection.close()
The code for receive_logs_topic.py:
- #!/usr/bin/env python
- import pika
- import sys
- connection = pika.BlockingConnection(pika.ConnectionParameters(
- host='localhost'))
- channel = connection.channel()
- channel.exchange_declare(exchange='topic_logs',
- type='topic')
- result = channel.queue_declare(exclusive=True)
- queue_name = result.method.queue
- binding_keys = sys.argv[1:]
- if not binding_keys:
- print >> sys.stderr, "Usage: %s [binding_key]..." % (sys.argv[0],)
- sys.exit(1)
- for binding_key in binding_keys:
- channel.queue_bind(exchange='topic_logs',
- queue=queue_name,
- routing_key=binding_key)
- print ' [*] Waiting for logs. To exit press CTRL+C'
- def callback(ch, method, properties, body):
- print " [x] %r:%r" % (method.routing_key, body,)
- channel.basic_consume(callback,
- queue=queue_name,
- no_ack=True)
- channel.start_consuming()
#!/usr/bin/env python
import pika
import sys connection = pika.BlockingConnection(pika.ConnectionParameters(
host='localhost'))
channel = connection.channel() channel.exchange_declare(exchange='topic_logs',
type='topic') result = channel.queue_declare(exclusive=True)
queue_name = result.method.queue binding_keys = sys.argv[1:]
if not binding_keys:
print >> sys.stderr, "Usage: %s [binding_key]..." % (sys.argv[0],)
sys.exit(1) for binding_key in binding_keys:
channel.queue_bind(exchange='topic_logs',
queue=queue_name,
routing_key=binding_key) print ' [*] Waiting for logs. To exit press CTRL+C' def callback(ch, method, properties, body):
print " [x] %r:%r" % (method.routing_key, body,) channel.basic_consume(callback,
queue=queue_name,
no_ack=True) channel.start_consuming()
3. 运行和结果
接收所有的log:
- python receive_logs_topic.py "#"
python receive_logs_topic.py "#"
接收所有kern facility的log:
- python receive_logs_topic.py "kern.*"
python receive_logs_topic.py "kern.*"
仅仅接收critical的log:
- python receive_logs_topic.py "*.critical"
python receive_logs_topic.py "*.critical"
可以创建多个绑定:
- python receive_logs_topic.py "kern.*" "*.critical"
python receive_logs_topic.py "kern.*" "*.critical"
Producer产生一个log:"kern.critical" type:
- python emit_log_topic.py "kern.critical" "A critical kernel error"
python emit_log_topic.py "kern.critical" "A critical kernel error"
课后思考题:
- Will "*" binding catch a message sent with an empty routing key?
- Will "#.*" catch a message with a string ".." as a key? Will it catch a message with a single word key?
- How different is "a.*.#" from "a.#"?
转载自: anzhsoft: http://blog.csdn.net/anzhsoft/article/details/19633079
参考资料:
1. http://www.rabbitmq.com/tutorials/tutorial-five-python.html
RabbitMQ 使用主题进行消息分发的更多相关文章
- RabbitMQ消息队列(六):使用主题进行消息分发[转]
在上篇文章RabbitMQ消息队列(五):Routing 消息路由 中,我们实现了一个简单的日志系统.Consumer可以监听不同severity(严重级别)的log.但是,这也是它之所以叫做简单日志 ...
- RabbitMQ基本用法、消息分发模式、消息持久化、广播模式
RabbitMQ基本用法 进程queue用于同一父进程创建的子进程间的通信 而RabbitMQ可以在不同父进程间通信(例如在word和QQ间通信) 示例代码 生产端(发送) import pika c ...
- RabbitMQ中交换机的消息分发机制
RabbitMQ是一个消息代理,它接受和转发消息,是一个由 Erlang 语言开发的遵循AMQP协议的开源实现.在RabbitMQ中生产者不会将消息直接发送到队列当中,而是将消息直接发送到交换机(ex ...
- (转)RabbitMQ消息队列(六):使用主题进行消息分发
在上篇文章RabbitMQ消息队列(五):Routing 消息路由 中,我们实现了一个简单的日志系统.Consumer可以监听不同severity的log.但是,这也是它之所以叫做简单日志系统的原因, ...
- RabbitMQ消息队列(六):使用主题进行消息分发
在上篇文章RabbitMQ消息队列(五):Routing 消息路由 中,我们实现了一个简单的日志系统.Consumer可以监听不同severity的log.但是,这也是它之所以叫做简单日志系统的原因, ...
- RabbitMQ 入门教程(PHP版) 第五部分:通过主题进行消息分发(Topics)
对于 Message 的 routing_key 字符串格式是有限制的:以点号"."分割的字符表,如php.laravel,并且长度不能超过 255 个字节. 对于 routing ...
- RabbitMq初探——消息分发
消息分发 前言 我们在用到消息队列的场景,一般是处理逻辑复杂,耗时,所以将同步改为异步处理,接入队列,下游处理耗时任务. 队列消息数量很大,且下游worker进程(消费者)处理耗时长,所以就有了任务的 ...
- RabbitMQ消息分发轮询和Message Acknowledgment
一.消息分发 RabbitMQ中的消息都只能存储在Queue中,生产者(下图中的P)生产消息并最终投递到Queue中,消费者(下图中的C)可以从Queue中获取消息并消费. 多个消费者可以订阅同一个Q ...
- 轻松搞定RabbitMQ(二)——工作队列之消息分发机制
转自 http://blog.csdn.net/xiaoxian8023/article/details/48681987 上一篇博文中简单介绍了一下RabbitMQ的基础知识,并写了一个经典语言入门 ...
随机推荐
- Hadoop环境搭建--Docker完全分布式部署Hadoop环境(菜鸟采坑吐血整理)
系统:Centos 7,内核版本3.10 本文介绍如何从0利用Docker搭建Hadoop环境,制作的镜像文件已经分享,也可以直接使用制作好的镜像文件. 一.宿主机准备工作 0.宿主机(Centos7 ...
- 【centos】/usr/bin与/usr/local/bin的区别
首先注意usr 指 Unix System Resource,而不是User 然后通常: /usr/bin下面的都是系统预装的可执行程序,会随着系统升级而改变. /usr/local/bin目录是给用 ...
- tiny4412--linux驱动学习(1)
1,概述 linux设备驱动分为三种:字符驱动设备.块驱动设备.网络设备 架构: 1,字符设备驱动 是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符 ...
- 关于TCP窗口大小
窗口字段 TCP Window字段用于接收端通知发送端:接收端当前能够接收的字节数(即当前允许发送端发送的字节数).在TCP Header中占有16bit长度,如下所示 0 1 2 3 0 1 2 3 ...
- java多线程管理 concurrent包用法详解
我们都知道,在JDK1.5之前,Java中要进行业务并发时,通常需要有程序员独立完成代码实现,当然也有一些开源的框架提供了这些功能,但是这些依然没有JDK自带的功能使用起来方便.而当针对高质量 ...
- CSS3扫描动画效果
.swiper-animate { position: absolute; width: 100%; height: 100%; left:; top:; z-index:; background: ...
- SystemUI中监听app启动,修改app中的状态栏背景色
参考 http://www.2cto.com/kf/201206/137225.html 从Android4.4开始,app可以自定义status bar 背景. 对于一些第三方app定义的状态栏背景 ...
- mac电脑Git提交代码到Github提示git-credential-osxkeychain 验证解决方案
## 啊哈哈 这个简单,直接给出当前mac电脑登录账号密码即可,^_*,拿走不谢!!
- canvas画布如何画图案例
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- 利用jsonp调用外部ip地址池
<html lang="en"> <head> <meta charset="UTF-8"> <title>Do ...