Python 操作 Rabbit MQ 主题交换机 (七)
一、主题交换机(Topic Exchange):
主题交换机的消息不可以携带随意的路由键(routing_key),它的路由键必须是一个由.
分隔开的词语列表。
- 建议:这些单词最好跟携带它们的消息有关系的词汇。比如:“quick.orange.rabbit”。
- 注意:词语的个数可以随意,但是不要超过255字节。
绑定键也必须拥有同样的格式。主题交换机跟直连交换机比较相似,一个携带着特定路由键的消息会被主题交换机投递给绑定键与想匹配的队列
。
绑定键跟路由键两个特殊应用方式:
*
星号:用来表示一个单词;#
井号:用来表示任意数量(零个或者多个)单词;
图解:
详解:
发送的消息所携带的路由键
是由三个单词组成,这三个单词被两个.
分割开。
图中创建了三个绑定:Q1的绑定键为:*.orange.*
,Q2的绑定键为:*. *. rabbit
和lazy.#
绑定键可总结为:
- Q1对所有桔黄色的事物都感兴趣;
- Q2对所有兔子和所有懒惰的事物感兴趣;
举栗子:
携带着有quick.orange.rabbit
的消息会被分别投递给两个队列中。
- Q1与Q2队列;
携带着lazy.orange.elephant
的消息也会被分别投递给两个队列中。
- Q1与Q2队列;
携带着quick.orange.fox
的消息仅会投递一个队列中。
- Q1队列;
携带着lazy.brown.fox
的消息会投递给一个队列中。
- Q2队列;
携带着lazy.pink.rabbit
的消息仅会投递给一个队列中。
- Q2队列;
携带着quick.brown.fox
的消息不会投递给任何一个队列中。
如果违反约定,发送一个携带有一个单词或者四个单词(orange 或者 quick.orange.male.rabbit
)的消息,发送消息不会投递给任何一个队列,而且会丢失掉。
lazy.orange.male.rabbit
有四个单词,不过它不会丢失,因为lazy.#
,#可匹配多个,会被投递到Q2队列中;
如果我们违反约定,发送了一个携带有一个单词或者四个单词("orange"
or "quick.orange.male.rabbit"
)的消息时,发送的消息不会投递给任何一个队列,而且会丢失掉。
但是另一方面,即使 "lazy.orange.male.rabbit"
有四个单词,他还是会匹配最后一个绑定,并且被投递到第二个队列中。
简单总结:
1.当一个队列的绑定键为
#
(井号)的时候,这个队列将会无视消息的路由键,接收所有的消息。2.当*(星号)和#(井号)这两个特殊字符都未在绑定键中出现,就可以理解`主题交换机就有用直连交换机的行为。
二、整合代码:
1.send.py
的代码:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import pika
import sys
routing_key = sys.argv[1] if len(sys.argv) > 1 else 'anonymous.info'
message = ' '.join(sys.argv[2:]) or "Hello World!"
# 创建一个实例 本地访问IP地址可以为 localhost 后面5672是端口地址(可>以不用指定, 因为默认就是5672)
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost', 5672))
# 声明一个管道, 在管道里发送消息
channel = connection.channel()
# 指定交换机名称:topic_logs 类型为:主题交换机
channel.exchange_declare(exchange='topic_logs', exchange_type='topic')
# 投递消息, 路由键
channel.basic_publish(exchange='topic_logs',
routing_key=routing_key,
body=message
)
print "[x] sent {}--{}".format(routing_key, message)
# 队列关闭
connection.close()
2.receive.py
的代码:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import pika
import sys
# 创建实例
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
# 声明管道
channel = connection.channel()
# 指定交换机名: topic_logs, 交换机的类型: 主题交换机
channel.exchange_declare(exchange='topic_logs', exchange_type='topic')
# 表示与消费者断开连接, 队列立即删除
result = channel.queue_declare(queue='', 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)
def callback(ch, method, properties, body):
print '[X] Received{}'.format(body,)
# 消费消息
channel.basic_consume(queue=queue_name, # 从指定的消息队列中接收消息
on_message_callback=callback, # 如果收到消息, 就调用callback函数来处理
)
print('=======正在等待消息========')
channel.start_consuming() # 开始消费消息
3.打开一个新的终端,执行下面命令,接收所有日志
:
python receive.py "#"
=======正在等待消息========
4.打开一个新的终端,执行下面命令,接收Django
的日志:
python receive.py "Django.*"
=======正在等待消息========
5.打开一个新的终端,执行下面命令,接收以py
结尾的日志:
python receive.py "*.py"
=======正在等待消息========
6.在打开一个新的终端,执行下面命令,建立多个绑定以Django开头或者js结尾
的日志:
python receive.py "Django.*" "*.js"
=======正在等待消息========
7.打开新的终端,执行下面命令,发送路由键为Django.py
的日志:
python send.py "Django.py" "send new message"
[x] sent Django.py--send new message
可以看到:以上的receive.py 文件都接收到了发出的消息:
=======正在等待消息 ========
[X] Receivedsend new message
如果执行:python send.py “fe_cow” “send error message”
可以看到,只有步骤3的队列才会处理消息:
=======正在等待消息 ========
[X] Receivedsend new message
[X] Receivedsend error message
三、查看当前队列信息:
1.查看当前已经绑定的队列列表:
rabbitmqctl list_bindings
Listing bindings ...
exchange amq.gen-A7-oPxJxMNdJFKp4rBLpRQ queue amq.gen-A7-oPxJxMNdJFKp4rBLpRQ []
exchange amq.gen-PxSynZTpkebC52Wyl7P7ag queue amq.gen-PxSynZTpkebC52Wyl7P7ag []
exchange amq.gen-hWwged-kY3-tzlWLY10K7g queue amq.gen-hWwged-kY3-tzlWLY10K7g []
exchange amq.gen-rVmLKIawWUNBQgJRQCv1ng queue amq.gen-rVmLKIawWUNBQgJRQCv1ng []
exchange hello queue hello []
exchange task_queue queue task_queue []
topic_logs exchange amq.gen-PxSynZTpkebC52Wyl7P7ag queue # []
topic_logs exchange amq.gen-rVmLKIawWUNBQgJRQCv1ng queue *.js []
topic_logs exchange amq.gen-A7-oPxJxMNdJFKp4rBLpRQ queue *.py []
topic_logs exchange amq.gen-hWwged-kY3-tzlWLY10K7g queue Django.* []
topic_logs exchange amq.gen-rVmLKIawWUNBQgJRQCv1ng queue Django.* []
交换机名:topic_logs 共绑定了5个队列。
2.查看当前交换器列表:
[root@iz2zeap40j01vg100ifsf4z /]# rabbitmqctl list_exchanges
Listing exchanges ...
amq.rabbitmq.log topic
amq.direct direct
amq.topic topic
amq.headers headers
direct_logs direct
fanout_logs fanout
direct
amq.fanout fanout
amq.rabbitmq.trace topic
topic_logs topic # 交换机名:topic_logs 类型为:主题交换机
amq.match headers
3.查看当前队列中的消息:
[root@iz2zeap40j01vg100ifsf4z /]# rabbitmqctl list_queues
Listing queues ...
hello 0
amq.gen-PxSynZTpkebC52Wyl7P7ag 2
amq.gen-A7-oPxJxMNdJFKp4rBLpRQ 1
amq.gen-rVmLKIawWUNBQgJRQCv1ng 1
task_queue 0
amq.gen-hWwged-kY3-tzlWLY10K7g 1