基於Python語言使用RabbitMQ消息隊列(四)

路由

在上一節我們構建了一個簡單的日誌系統。我們能夠廣播消息給很多接收者。

在本節我們將給它添加一些特性——我們讓它只訂閱所有消息的子集。例如,我們只把嚴重錯誤(critical error)導入到日誌文件(存入磁盤空間),但仍然可以打印所有日誌消息到控制檯。

綁定

前面的例子中我們已經創建了綁定,像下面這樣:

channel.queue_bind(exchange=exchange_name,
                   queue=queue_name)

綁定是一個交易所和一個隊列之間的關係。這可以解釋爲:一個隊列對源於這個交易所的消息感興趣。
綁定可以採用一個額外的routing_key 參數。爲避免同basic_publish參數混淆,我們稱呼它爲綁定鍵(binding key)。我們用一個鍵來創建一個綁定This is how we could create a binding with a key:

channel.queue_bind(exchange=exchange_name,
                   queue=queue_name,
                   routing_key='black')

一個綁定鍵的意義取決於交易所類型。我們先前使用過的fanout類型交易所就會忽略它的值。

直接型交易所(Direct exchange)

我們先前的日誌系統會廣播所有消息給所有消費者。我們現在想擴展它讓過濾掉一些消息,基於這些消息的嚴重級別。例如我們可能想要向磁盤寫日誌的腳本只接收嚴重錯誤critical error,不要浪費磁盤空間在warning或info日誌上面。

我們正使用的fanout類型交易所不會給我們太大的靈活性——它只能夠無意識地進行廣播。

我們會使用直接型交易所進行替代,直接型交易所背後的路由算法很簡單——一條消息會前往綁定鍵(binding key)恰巧匹配這條消息的路由鍵(routing key)的隊列。
爲了闡釋這個問題,考慮下圖的設定:
這裏寫圖片描述
在這個設定當中我們看到直接型交易所X有兩個隊列與之綁定。第一個隊列的綁定鍵爲“orange”,第二個有兩個綁定鍵,一個是“black”,另一個是“green”。

在這個設定中,發佈到交易所中的帶有路由鍵“orange”的會被路由到隊列Q1。帶有路由鍵“black”和“green”的會前往Q2。所有其他的消息會被忽略。

多重綁定

這裏寫圖片描述
使用相同的綁定鍵綁定多個隊列完全沒有問題。在我們的例子中我們可以用綁定鍵“black”在交易所X和隊列Q1之間添加綁定。這樣的話,direct型交易所就會表現的像fanout交易所,廣播消息給所有匹配的隊列。具有“black”路由鍵的消息會被傳送給Q1和Q2。

生成日誌

我們會爲日誌系統使用這個模型。發送消息到direct交易所,而非fanout交易所。我們會提供日誌級別(log severity)作爲路由鍵。這樣接收腳本就能夠選擇它想要的級別來接收。我們首先關注生成日誌。

像通常我們需要創建一個交易所時那樣:

channel.exchange_declare(exchange='direct_logs',
                         type='direct')

準備好發送消息:

channel.basic_publish(exchange='direct_logs',
                      routing_key=severity,
                      body=message)

爲了使事情簡單我們假設’severity’ 是 ‘info’, ‘warning’, ‘error’中的一種。

訂閱

接收消息就跟之前的教程中一樣,不同的是——我們要爲每種severity創建一個新的綁定。

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

for severity in severities:
    channel.queue_bind(exchange='direct_logs',
                       queue=queue_name,
                       routing_key=severity)

整合

這裏寫圖片描述
emit_log_direct.py完整代碼:

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

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

channel.exchange_declare(exchange='direct_logs',
                         type='direct')

severity = sys.argv[1] if len(sys.argv) > 2 else 'info'
message = ' '.join(sys.argv[2:]) or 'Hello World!'
channel.basic_publish(exchange='direct_logs',
                      routing_key=severity,
                      body=message)
print(" [x] Sent %r:%r" % (severity, message))
connection.close()

receive_logs_direct.py完整代碼:

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

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

channel.exchange_declare(exchange='direct_logs',
                         type='direct')

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

severities = sys.argv[1:]
if not severities:
    sys.stderr.write("Usage: %s [info] [warning] [error]\n" % sys.argv[0])
    sys.exit(1)

for severity in severities:
    channel.queue_bind(exchange='direct_logs',
                       queue=queue_name,
                       routing_key=severity)

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()

我在自己的Ubuntu終端開啓了三個控制檯,兩個用來接收日誌消息,其中一個設置爲只接收error日誌,並把收到的日誌存入日誌文件。另一個接收info,warning和error,直接打印到屏幕。如下圖:
寫入文件:
這裏寫圖片描述
打印到屏幕:
這裏寫圖片描述

生成日誌:
這裏寫圖片描述
查看日誌文件確實只收到了error日誌:
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章