讀古今文學網 > OpenStack系統架構設計實戰 > 2.7.2 消息隊列(AMQP) >

2.7.2 消息隊列(AMQP)

AMQP即Advanced Message Queuing Protocol,是一個提供統一消息服務的應用層標準高級消息隊列協議,是應用層協議的一個開放標準,為面向消息的中間件而設計。基於此協議的客戶端與消息中間件可傳遞消息,並不受客戶端/中間件不同產品、不同開發語言等條件的限制。典型的AMQP的產品實現有RabbitMQ和Qpid。OpenStack廣泛使用消息隊列作為組件間通信的中間件。

消息隊列協議規範AMQP定義了一種消息隊列傳輸模型。AMQP的消息模型概念主要是兩個組件:Exchange和Queue,如圖2-6所示。X就是Exchange,條狀的條是Queue,這兩者都在Server端,又稱作Broker,這部分由服務器實現。客戶端通常有Producer和Consumer兩種類型,Producer與Consumer通過TCP連接RabbitMQ,按照規範定義的信令交互協議,通過服務器發送或接收消息。

Client分為兩種角色,一種是消息發送方,如圖2-6中P所示(Provider,消息發送者);一種是消息接收方,如圖2-6中C所示(Consumer,消息接收者)。Client所傳遞的消息需通過服務器進行轉發。

圖2-6 AMQP的消息模型示意

交換器(Exchange)是交換消息的實體,起到消息路由、過濾的作用。隊列(Queue)是接收消息的實體,本質上是一個緩存消息的隊列。綁定器(Bind)將交換器和隊列連接起來,並且封裝消息的路由信息。

交換器指向隊列的黑色線——RoutingKey,可以將它簡單地理解為一條連接交換器和隊列的路線,交換器和隊列都需要通過Channel來進行定義,而RoutingKey則只需要在綁定時取個名稱就行了。

圖2-6中左邊的客戶向右邊的客戶發送消息,流程如下:

1)獲取Connection(客戶端到MQ服務器的TCP鏈路)。

2)獲取Channel(邏輯層的鏈路,基於Connection)。

3)定義交換器、隊列。

4)使用一個RoutingKey將隊列綁定到一個交換器上。

5)通過指定一個交換器和一個RoutingKey來將消息發送到對應的隊列上。

6)接收方在接收時也是獲取Connection,接著獲取Channel,然後指定一個隊列直接到它關心的隊列上取消息,它對交換器、RoutingKey及如何綁定都不關心,到對應的隊列上去取消息就行了。

一個客戶發送消息,哪些Client可以收到消息,其核心就在於交換器、RoutingKey、隊列的關係上。

交換器在定義的時候是有類型的,以決定到底是哪些隊列符合條件,可以接收消息,OpenStack中使用的交換器類型主要有以下3種。

1)Fanout:所有綁定到此交換器的隊列都可以接收消息。此為(publisher/subscriber)模式。

2)Direct:通過RoutingKey和交換器決定的那個唯一的隊列可以接收消息,此為1對1模式。

3)Topic:所有符合RoutingKey(可以是一個表達式)的RoutingKey所綁定的隊列可以接收消息,和扇出相比,這個相當於通過RoutingKey進行了過濾。

使用RoutingKey為#、交換器類型為topic的時候,相當於使用扇出。

以nova-api收到外部請求創建虛擬機為例。nova-api通過rpc.cast函數封裝,通過消息隊列發送消息給nova-scheduler,觸發nova-scheduler來調度nova-compute創建虛擬機。

rpc.cast(context, FLAGS.scheduler_topic, {"method": "run_instance", "args": {"topic": FLAGS.compute_topic,"instance_id": instance_id,"availability_zone": availability_zone,"injected_files": injected_files}})

第二個參數即為調度器關心的topic,系統中設定的值為scheduler,表明該消息需要nova-scheduler來接收並處理;第三個參數是消息體,使用的是key/value值對,method對應的run_instance表明這是一條創建虛擬機的消息。第一個參數context是上下文通用環境,其他參數編入到args參數里傳遞給nova-scheduler。