RabbitMQ官網教程3——發佈訂閱

        前面我們創建了工作隊列,工作隊列中每個任務只分發給一個worker。現在我們要把一個消息分發給多個消費者,這種模式就是發佈訂閱。爲解釋這種模式,我們將構建一個簡單的日誌系統,它包括兩個程序——一個提交日誌,另一個接收並打印。日誌系統中每個接收程序的拷貝都會收到消息,這樣可以一個將日誌寫入磁盤,另一個輸出到屏幕。本質上講,發佈的日誌消息被廣播給了所有的消費者。

 

交換機

        前面的章節我們說消息發送到隊列或是從隊列接收消息。現在是時候介紹一下Rabbit中的消息模型了。生產者發送消息,隊列存儲消息,消費者接收消息。RabbitMQ中消息模型的核心是,生產者不能直接將消息發送給隊列。實際上,大多數情況生產者甚至根本不知道把消息發送到哪個隊列。生產者只能將消息發送到交換機。交換機很簡單,一方面它從生產者接收消息,另一方面把消息推送到隊列。交換機必須知道如何處理收到的消息。是該推送到一個特定的隊列?還是推送到多個隊列?還是丟棄?交換機類型定義了處理的規則。幾種交換機類型:direct、topic、headers、fanout。現在先只看fanout。創建一個名爲logs的該類型的交換機:

        channel.exchange_declare(exchange='logs',type='fanout')

fanout類型的交換機會廣播所有收到的消息給所有它知道的隊列。這正是我們的日誌系統需要的。

        列出服務裏的交換機可以使用rabbitmqctl:

        sudo rabbitmqctl list_exchanges

        匿名交換機,前面的章節我們使用了默認交換機,由空字符串標識:

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

參數exchange就是交換機的名字,空字符串表示默認或匿名交換機,消息被路由到由routing_key指定名字的隊列,如果它存在的話。

        現在,我們可以將消息發佈到命名的交換機了:

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

 

臨時隊列

        之前我們使用的隊列都是有特定名字的。給隊列命名很關鍵,我們需要把workers指定到相同的隊列。當我們想在生產者和消費者間共享隊列時,給隊列命名很重要。

        但是我們的日誌系統不是這種情況。我們想收到所有的消息,而不是一個子集。我們只關心當前的消息而不是舊的。我們需要這樣做:

        首先,當我們連接到Rabbit我們需要一個新的空隊列。我們可以使用隨機的名字最好讓服務爲我們選一個名字來創建隊列,只要我們不提供queue參數給queue_declare即可:

        result = channel.queue_declare()

result.method.queue就包含一個隨機的隊列名。

        其次,我們斷開連接,隊列應該被刪除,exclusive參數可以做到:

        result =channel.queue_declare(exclusive=True)

 

綁定

        我們需要告訴交換機將消息發送到隊列,交換機和隊列之間的關係稱爲綁定。

        channel.queue_bind(exchange='logs',queue=result.method.queue)

        列出綁定,可以使用sudo rabbitmqctl list_bindings


提交log:

import pika
import sys

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

channel.exchange_declare(exchange='logs', type='fanout')

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

        創建連接後,聲明交換機,這步很必要,因爲發佈到一個不存在的交換機是被禁止的。

        如果還沒有隊列綁定到交換機,消息將被丟棄。

接收log:

import pika

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

channel.exchange_declare(exchange='logs', type='fanout')

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

channel.queue_bind(exchange='logs', queue=queue_name)

print(' [*] Waiting for logs. To exit press CTRL+C')

def callback(ch, method, properties, body):
    print(" [x] %r" % body)

channel.basic_consume(callback, queue=queue_name, no_ack=True)

channel.start_consuming()


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