python3 RabbitMQ ( Topics!)

准备知识

What This Tutorial Focuses On

在前面的教程中,我们改进了日志系统。我们没有使用只能进行虚拟广播的扇出交换,而是使用了直接交换,并获得了选择性地接收日志的可能性。
虽然使用direct exchange改进了我们的系统,但是它仍然有局限性——它不能基于多个标准进行路由。

在我们的日志系统中,我们可能不仅要根据严重性订阅日志,还要根据发出日志的源订阅日志。您可能从syslog unix工具中了解了这个概念,该工具根据严重性(info/warn/crit…)和功能(auth/cron/kern…)来路由日志。

这将给我们带来很大的灵活性——我们可能只希望听到来自“cron”的关键错误,但也希望听到来自“kern”的所有日志。

要在日志系统中实现这一点,我们需要了解更复杂的主题交换。

Topic exchange

发送到主题交换的消息不能有任意的routing_key——它必须是由点分隔的单词列表。单词可以是任何东西,但通常它们指定了与消息相关的一些特性。一些有效的路由关键示例:“stock.usd。”纽交所”、“纽交所。vmw”、“quick.orange.rabbit”。路由键中可以有任意多的单词,最多255字节。

绑定键的形式也必须相同。主题交换背后的逻辑类似于直接交换——使用特定路由键发送的消息将被传递到使用匹配绑定键绑定的所有队列。但是,绑定键有两个重要的特殊情况:

  • *(星号)只能代替一个单词。
  • #(哈希)可以替代0个或多个单词。

这是最容易解释的一个例子:
python3 RabbitMQ ( Topics!)_第1张图片

在这个例子中,我们将发送所有描述动物的信息。消息将通过一个由三个单词(两个点)组成的路由键发送。路由键中的第一个单词将描述一个快速,第二个单词描述颜色,第三个单词描述一个物种:“..”。

We created three bindings: Q1 is bound with binding key “.orange.” and Q2 with “..rabbit” and “lazy.#”.

这些绑定可以总结为:

  • Q1对所有橙色的动物都感兴趣。
  • Q2想听关于兔子的一切,关于懒惰的动物的一切。

A message with a routing key set to “quick.orange.rabbit” will be delivered to both queues. Message “lazy.orange.elephant” also will go to both of them. On the other hand “quick.orange.fox” will only go to the first queue, and “lazy.brown.fox” only to the second. “lazy.pink.rabbit” will be delivered to the second queue only once, even though it matches two bindings. “quick.brown.fox” doesn’t match any binding so it will be discarded.

What happens if we break our contract and send a message with one or four words, like “orange” or “quick.orange.male.rabbit”? Well, these messages won’t match any bindings and will be lost.

On the other hand “lazy.orange.male.rabbit”, even though it has four words, will match the last binding and will be delivered to the second queue.

Topic exchange
主题交换功能强大,可以像其他交换一样进行。

当一个队列被“#”(哈希)绑定键绑定时——它将接收所有的消息,不管路由键是什么——就像扇出交换一样。

当绑定中没有使用特殊字符“*”(星号)和“#”(散列)时,主题交换的行为将与直接交换一样。

Putting it all together

我们将在日志系统中使用主题交换。我们首先假设日志的路由键有两个字:“.”。

#!/usr/bin/env python
import pika
import sys

connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()

channel.exchange_declare(exchange='topic_logs',
                         exchange_type='topic')

routing_key = sys.argv[1] if len(sys.argv) > 2 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()

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',
                         exchange_type='topic')

result = channel.queue_declare(exclusive=True)
queue_name = result.method.queue

binding_keys = sys.argv[1:]
if not binding_keys:
    sys.stderr.write("Usage: %s [binding_key]...\n" % 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()

你可能感兴趣的:(RabbitMQ)