前面的一小节路由键是精确匹配的,
路由键的功能,通过设置路由键,可以将消息发送到相应的队列,这里的路由键是要完全匹配,比如info消息的只能发到路由键为
info的消息队列。有时用需要路由键模糊匹配,本篇主要演示了路由键模糊匹配的工作方式,主要依赖于使用另一种更复杂的交换
机—— 主题交换机。
一、主题交换机
1、发送到主题交换机(topic exchange)的消息不可以携带随意什么样子的路由键(routing_key),它的路由键必须是一个由.分
隔开的词语列表。这些单词随便是什么都可以,但是最好是跟携带它们的消息有关系的词汇。
例子:"stock.usd.nyse", "nyse.vmw", "quick.orange.rabbit"。词语的个数可以随意,但是不要超过255字节。
2、绑定键也必须拥有同样的格式。主题交换机背后的逻辑跟直连交换机很相似 —— 一个携带着特定路由键的消息会被主题交换
机投递给绑定键与之想匹配的队列。但是它的绑定键和路由键有两个特殊应用方式:
"*" (星号) 用来表示一个单词。(必须出现的)
"#" (井号) 用来表示任意数量(零个或多个)单词。
3、大家可以根据下图,猜测哪些路由键会被发送到相应的队列,就是类似于正则的匹配,但是比正则简单太多了,有兴趣的可以到
官网查看完整内容,我就不再阐述了。
4、主题交换机
当一个队列的绑定键为 "#"(井号) 的时候,这个队列将会无视消息的路由键,接收所有的消息。
当 * (星号) 和 # (井号) 这两个特殊字符都未在绑定键中出现的时候,此时主题交换机就拥有的直连交换机的行为。
所以主题交换机也就实现了扇形交换机的功能,和直连交换机的功能。
二、实例演示
send.py表示发送端,receive.py表示接收端。实例的功能大概是这样:比如你有个知心好朋友,不管开心、伤心、工作上的还是生
活上的事情都可以和她说;还有一些朋友可以分享开心的事情;还有一些朋友,你可以把不开心的事情和她说。
1、生产者
(1) 创建连接和通道
(2) 创建交换机(主题交换机)
(3) 发送消息到指定交换机,并将消息中指定routing_key(注意key的规则)
2、消费者
(1) 创建连接和通道
(2) 创建交换机(主题交换机)
(3) 创建匿名队列(每个消费者都要创建的独立的队列,用于接收路由后消息)
(4) 创建绑定(通过路由键绑定交换机队列关系,确定队列处理交换机中的哪些消息,注意路由键的正则规则)
(5) 在指定交换机处理消息
3、程序
(1)、send.py
因为要进行路由键模糊匹配,所以交换机的类型要设置为topic,设置为topic,就可以使用#,*的匹配符号了。
#!/usr/bin/python
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
#定义交换机,设置类型为topic
channel.exchange_declare(exchange='messages', type='topic')
#定义路由键
routings = ['happy.work', 'happy.life', 'sad.work', 'sad.life']
#将消息依次发送到交换机,并设定路由键
for routing in routings:
message = '%s message.' % routing
channel.basic_publish(exchange='messages',routing_key=routing,body=message) #将携带路由键的消息依次发给交换机
print message
connection.close()
(2)、receive.py
交换机的类型要设定为topic就可以了。从命令行接收参数的功能稍微调整了一下,就是没有参数时报错退出。
#!/usr/bin/python
import pika, sys
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
#定义交换机,设置类型为topic
channel.exchange_declare(exchange='messages', type='topic')
#从命令行获取路由参数,如果没有,则报错退出
routings = sys.argv[1:]
if not routings: #取反
print "Usage: %s [routing_key]..." % (sys.argv[0],)
exit()
#生成临时队列,并绑定到交换机上,设置路由键
result = channel.queue_declare(exclusive=True)
queue_name = result.method.queue
for routing in routings:
channel.queue_bind(exchange='messages',queue=queue_name,routing_key=routing)
def callback(ch, method, properties, body):
print " [x] Received %s" % (body,)
channel.basic_consume(callback, queue=queue_name, no_ack=True)
print ' [*] Waiting for messages. To exit press CTRL+C'
channel.start_consuming()
打开四个终端,一个运行如下,表示任何事情都可以和她说:python receive.py "#"
另外一个终端 运行如下,表示可以和她分享开心的事:python receive.py "happy.*"
第三个运行如下,表示工作上的事情可以和她分享:python receive.py "*.work"
最后一个运行python send.py。可得到程序的运行结果。
三、官网提出的几个问题
1、发送消息时,如果路由键设置为”..”,那么路由键设置为”#.*”的接收端是否能接收到消息?如果发送消息时,路由键设置
为一个词呢?
两种情况,笔者都测试过了,可以的。
2、”a.*.#” 和”a.#”的区别
"a.#"只要字符串开头的一个词是a就可以了,比如a、a.haha、a.haha.haha。而这样的词是不行的,如abs、abc、abc.haha。
"a.*.#"必须要满足a.*的字符串才可以,比如a.、a.haha、a.haha.haha。而这样的词是不行的,如a。
我觉得根据官网和别人的博客总结,最终还是很清楚的把主题交换机搞清楚了。所以说,灵活运用,根据应用场景合理选择不同的
交换机!主题交换机进行路由的模糊匹配就到这里。