1. 程式人生 > >openstack分析——NOVA中的RabbitMQ解析

openstack分析——NOVA中的RabbitMQ解析

轉載自:http://blog.csdn.net/gaoxingnengjisuan

相關文章:

http://blog.csdn.net/gaoxingnengjisuan/article/category/1461395/2

    本篇文章是由本人閱讀NOVA原始碼過程中的心得、RabbitMQ的官方文件以及網上的一些資料整理總結而成的,也為了方便以後對這部分內容的複習。

    NOVA是OpenStack系統的核心模組,主要負責虛擬機器例項的生命週期管理、網路管理(前幾個版本)、儲存卷管理(前幾個版本)、使用者管理以及其他相關雲平臺管理功能,在能力上類似於Amazon EC2和Rackspace Cloud Servers。

訊息佇列(Queue)與資料庫(Database)作為Nova總體架構中的兩個重要組成部分,二者通過系統內訊息傳遞和資訊共享的方式實現任務之間、模組之間、介面之間的非同步部署,在系統層面大大簡化了複雜任務的排程流程與模式,是整個OpenStack Nova系統的核心功能模組。終端使用者(DevOps、Developers和其他OpenStack元件)主要通過Nova API實現與OpenStack系統的互動,同時Nova守護程序之間通過訊息佇列和資料庫來交換資訊以執行API請求,完成終端使用者的雲服務請求。

    Nova採用無共享、基於訊息的靈活架構,意味著Nova的元件有多種安裝方式,可以將每個Nova-Service模組單獨安裝在一臺伺服器上,同時也可以根據業務需求將多個模組組合安裝在多臺伺服器上。

1.RabbitMQ

    OpenStack Nova系統目前主要採用RabbitMQ作為資訊交換中樞。

    RabbitMQ是一種處理訊息驗證、訊息轉換和訊息路由的架構模式,它協調應用程式之間的資訊通訊,並使得應用程式或者軟體模組之間的相互意識最小化,有效實現解耦。

    RabbitMQ適合部署在一個拓撲靈活易擴充套件的規模化系統環境中,有效保證不同模組、不同節點、不同程序之間訊息通訊的時效性;而且,RabbitMQ特有的叢集HA安全保障能力可以實現資訊樞紐中心的系統級備份,同時單節點具備訊息恢復能力,當系統程序崩潰或者節點宕機時,RabbitMQ正在處理的訊息佇列不會丟失,待節點重啟之後可根據訊息佇列的狀態資料以及資訊資料及時恢復通訊。

    RabbitMQ在功能性、時效性、安全可靠性以及SLA方面的出色能力可有效支援OpenStack雲平臺系統的規模化部署、彈性擴充套件、靈活架構以及資訊保安的需求。

2.AMQP

    AMQP是應用層協議的一個開放標準,為面向訊息的中介軟體而設計,其中RabbitMQ是AMQP協議的一個開源實現,OpenStack Nova各軟體模組通過AMQP協議實現資訊通訊。AMQP協議的設計理念與資料通訊網路中的路由協議非常類似,可歸納為基於狀態的面向無連線通訊系統模式。不同的是,資料通訊網路是基於通訊鏈路的狀態決定客戶端與服務端之間的連結,而AMQP是基於訊息佇列的狀態決定訊息生產者與訊息消費者之間的連結。對於AMQP來講,訊息佇列的狀態資訊決定通訊系統的轉發路徑,連結兩端之間的鏈路並不是專用且永久的,而是根據訊息佇列的狀態與屬性實現資訊在RabbitMQ伺服器上的儲存與轉發,正如資料通訊網路的IP資料包轉發機制,所有的路由器是基於通訊鏈路的狀態而形成路由表,IP資料包根據路由表實現報文的本地儲存與逐級轉發,二者在實現機制上具有異曲同工之妙。

    AMQP的目標是實現端到端的資訊通訊,那麼必然涉及兩個基本的概念:AMQP實現通訊的因素是什麼以及AMQP實現通訊的實體以及機制是什麼。

    AMQP是面向訊息的一種應用程式之間的通訊方法,也就是說,“訊息”是AMQP實現通訊的基本因素。AMQP有兩個核心要素——交換器(Exchange)與佇列(Queue)通過訊息的繫結與轉發機制實現資訊通訊。其中,交換器是由消費者應用程式建立,並且可與其他應用程式實現共享服務,其功能與資料通訊網路中的路由器非常相似,即接收訊息之後通過路由表將訊息準確且安全的轉發至相應的訊息佇列。一臺RabbitMQ伺服器或者由多臺RabbitMQ伺服器組成的叢集可以存在多個交換器,每個交換器通過唯一的Exchange ID進行識別。

    交換器根據不同的應用程式的需求,在生命週期方面也是靈活可變的,主要分為三種:持久交換器、臨時交換器與自動刪除交換器。持久交換器是在RabbitMQ伺服器中長久存在的,並不會因為系統重啟或者應用程式終止而消除,其相關資料長期駐留在硬碟之上;臨時交換器駐留在記憶體中,隨著系統的關閉而消失;自動刪除交換器隨著宿主應用程式的中止而自動消亡,可有效釋放伺服器資源。

    佇列也是由消費者應用程式建立,主要用於實現儲存與轉發交換器傳送來的訊息,佇列同時也具備靈活的生命週期屬性配置,可實現佇列的持久儲存、臨時駐留與自動刪除。

    由以上可以看出,訊息、佇列和交換器是構成AMQP的三個關鍵元件,任何一個元件的實效都會導致資訊通訊的中斷,因此鑑於三個關鍵元件的重要性,系統在建立三個元件的同時會打上“Durable”標籤,表明在系統重啟之後立即恢復業務功能。

    以上主要介紹構成AMQP的三個關鍵要素,那麼它們之間是如何工作的呢?

    由圖中可以看出,交換器接收發送端應用程式的訊息,通過設定的路由轉發表與繫結規則將訊息轉發至相匹配的訊息佇列,訊息佇列繼而將接收到的訊息轉發至對應的接收端應用程式。資料通訊網路通過IP地址形成的路由表實現IP報文的轉發,在AMQP環境中的通訊機制也非常類似,交換器通過AMQP訊息頭(Header)中的路由選擇關鍵字(Routing Key)而形成的繫結規則(Binding)來實現訊息的轉發,也就是說,“繫結”即連線交換機與訊息佇列的路由表。訊息生產者傳送的訊息中所帶有的Routing Key是交換器轉發的判斷因素,也就是AMQP中的“IP地址”,交換器獲取訊息之後提取Routing Key觸發路由,通過繫結規則將訊息轉發至相應佇列,訊息消費者最後從佇列中獲取訊息。AMQP定義三種不同型別的交換器:廣播式交換器(Fanout Exchange)、直接式交換器(Direct Exchange)和主題式交換器(Topic Exchange),三種交換器實現的繫結規則也有所不同。

3.Nova中的RabbitMQ應用

3.1RabbitMQ在Nova中的實現

    RabbitMQ是OpenStackNova系統的資訊中樞,目前Nova中的各個模組通過RabbitMQ伺服器以RPC(遠端過程呼叫)的方式實現通訊,而且各模組之間形成鬆耦合關聯關係,在擴充套件性、安全性以及效能方面均體現優勢。由前文可知,AMQP的交換器有三種類型:Direct、Fanout和Topic,而且訊息佇列是由訊息消費者根據自身的功能與業務需求而生成。

    首先說說三個比較重要的概念:

交換器:

    接受訊息並且將訊息轉發給佇列。在每個尋你主機的內部,交換器有唯一對應的名字。應用程式在他的許可權範圍之內可以建立、刪除、使用 和共享交換器例項。交換器可以是持久的,臨時的或者自動刪除的。持久的交換器會一直存在於Server端直到他被顯示的刪除;臨時交換器在伺服器關閉時停 止工作;自動刪除的交換器在沒有應用程式使用它的時候被伺服器刪除。

佇列:

    “訊息佇列”,它是一個具名緩衝區,它代表一組消費者應用程式儲存訊息。這些應用程式在它們的許可權範圍內可以建立、使用、共享訊息佇列。類似於交換器,訊息佇列也可以是持久的,臨時的或者自動刪除的。臨時訊息佇列在伺服器被關閉時停止工作;自動刪除佇列在沒有應用程式使用它的時候被伺服器自動刪 除。訊息佇列將訊息儲存在記憶體、硬碟或兩者的組合之中。訊息佇列儲存訊息,並將訊息發給一個或多個客戶端,特別的訊息佇列會跟蹤訊息的獲取情況,訊息要出對就必須被獲取,這樣可以阻止多個客戶端同時消費同一條訊息的情況發生,同時也可以被用來做單個佇列多個消費者之間的負載均衡。

繫結:

    可以理解為交換器和訊息佇列之間的一種關係,繫結之後交換器會知道應該把訊息發給那個佇列,繫結的關鍵字稱為binding_key。在程式中我們這樣使用:

    channel.queue_bind(exchange='direct_logs',queue=queue_name,routing_key=binding_key)

    Exchange和Queue的繫結可以是多對多的關係,每個傳送給Exchange的訊息都會有一個叫做routing_key的關鍵字,交換器要想把訊息傳送給某個特定的佇列,那麼該佇列與交換器的binding_key必須和訊息的routing_key相匹配才OK。

    介紹一下RabbitMQ的三種類型的交換器:

廣播式交換器型別(fanout

    該類交換器不分析所接收到訊息中的Routing Key,預設將訊息轉發到所有與該交換器繫結的佇列中去。廣播式交換器轉發效率最高,但是安全性較低,消費者應用程式可獲取本不屬於自己的訊息。

    廣播交換器是最簡單的一種型別,就像我們從字面上理解到的一樣,它把所有接受到的訊息廣播到所有它所知道的佇列中去,不論訊息的關鍵字是什麼,訊息都會被路由到和該交換器繫結的佇列中去。

    它的工作方式如下圖所示:

    在程式中申明一個廣播式交換器的程式碼如下:

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

直接式交換器型別(direct

    該類交換器需要精確匹配Routing Key與BindingKey,如訊息的Routing Key = Cloud,那麼該條訊息只能被轉發至Binding Key = Cloud的訊息佇列中去。直接式交換器的轉發效率較高,安全性較好,但是缺乏靈活性,系統配置量較大。

    相對廣播交換器來說,直接交換器可以給我們帶來更多的靈活性。直接交換器的路由演算法很簡單——一個訊息的routing_key完全匹配一個佇列的 binding_key,就將這個訊息路由到該佇列。繫結的關鍵字將佇列和交換器繫結到一起。當訊息的routing_key和多個繫結關鍵字匹配時訊息 可能會被髮送到多個佇列中。

    我們通過下圖來說明直接交換器的工作方式:

    如圖:Q1,Q2兩個佇列繫結到了直接交換器X上,Q1的binding_key是“orange”,Q2有兩個繫結,一個binding_key是black,另一個binding_key是green。在這樣的關係下,一個帶有 “orange” routing_key的訊息傳送到X交換器之後將會被X路由到佇列Q1,一個帶有 “black” 或者 “green”  routing_key的訊息傳送到X交換器之後將會被路由到Q2。而所有其他訊息將會被丟失掉。

主題式交換器(Topic Exchange

    該類交換器通過訊息的Routing Key與Binding Key的模式匹配,將訊息轉發至所有符合繫結規則的佇列中。Binding Key支援萬用字元,其中“*”匹配一個片語,“#”匹配多個片語(包括零個)。例如,Binding Key=“*.Cloud.#”可轉發Routing Key=“OpenStack.Cloud.GD.GZ”、“OpenStack.Cloud.Beijing”以及“OpenStack.Cloud”的訊息,但是對於Routing Key=“Cloud.GZ”的訊息是無法匹配的。

    這裡的routing_key可以使用一種類似正則表示式的形式,但是特殊字元只能是“*”和“#”,“*”代表一個單詞,“#”代表0個或是多個單詞。這樣傳送過來的訊息如果符合某個queue的routing_key定義的規則,那麼就會轉發給這個queue。

在Nova中主要實現Direct和Topic兩種交換器的應用在系統初始化的過程中,各個模組基於Direct交換器針對每一條系統訊息自動生成多個佇列注入RabbitMQ伺服器中,依據Direct交換器的特性要求,Binding Key=“MSG-ID”的訊息佇列只會儲存與轉發Routing Key=“MSG-ID”的訊息。同時,各個模組作為訊息消費者基於Topic交換器自動生成兩個佇列注入RabbitMQ伺服器中。

    Nova各個模組之間基於AMQP訊息實現通訊,但是真正實現訊息呼叫的應用流程主要是RPC機制。Nova基於RabbitMQ實現兩種RPC呼叫:RPC.CALL和RPC.CAST,其中RPC.CALL基於請求與響應方式,RPC.CAST只是提供單向請求,兩種RPC呼叫方式在Nova中均有不同的應用場景。

    Nova的各個模組在邏輯功能是可以劃分為兩種:Invoker和Worker,其中Invoker模組主要功能是向訊息佇列中傳送系統請求訊息,如Nova-API和Nova-Scheduler;Worker模組則從訊息佇列中獲取Invoker模組傳送的系統請求訊息以及向Invoker模組回覆系統響應訊息,如Nova-Compute、Nova-Volume和Nova-Network。Invoker通過RPC.CALL和RPC.CAST兩個程序傳送系統請求訊息;Worker從訊息佇列中接收訊息,並對RPC.CALL做出響應。Invoker、Worker與RabbitMQ中不同型別的交換器和佇列之間的通訊關係如圖所示。

    Nova根據Invoker和Worker之間的通訊關係可邏輯劃分為兩個交換域:Topic交換域與Direct交換域,兩個交換域之間並不是嚴格割裂,在資訊通訊的流程上是深度嵌入的關係。Topic交換域中的Topic訊息生產者(Nova-API或者Nova-Scheduler)與Topic交換器生成邏輯連線,通過PRC.CALL或者RPC.CAST程序將系統請求訊息發往Topic交換器。Topic交換器根據系統請求訊息的Routing Key分別送入不同的訊息佇列進行轉發,如果訊息的Routing Key=“NODE-TYPE.NODE-ID”,則將被轉發至點對點訊息佇列;如果訊息的Routing Key=“NODE-TYPE”,則將被轉發至共享訊息佇列。Topic訊息消費者探測到新訊息已進入響應佇列,立即從佇列中接收訊息並呼叫執行系統訊息所請求的應用程式。每一個Worker都具有兩個Topic訊息消費者程式,對應點對點訊息佇列和共享訊息佇列,連結點對點訊息佇列的Topic訊息消費者應用程式接收RPC.CALL的遠端呼叫請求,並在執行相關計算任務之後將結果以系統響應訊息的方式通過Direct交換器反饋給Direct訊息消費者;同時連結共享訊息佇列的Topic訊息消費者應用程式只是接收RPC.CAST的遠端呼叫請求來執行相關的計算任務,並沒有響應訊息反饋。因此,Direct交換域並不是獨立運作,而是受限於Topic交換域中RPC.CALL的遠端呼叫流程與結果,每一個RPC.CALL啟用一次Direct訊息交換的運作,針對每一條系統響應訊息會生成一組相應的訊息佇列與交換器組合。因此,對於規模化的OpenStack雲平臺系統來講,Direct交換域會因大量的訊息處理而形成整個系統的效能瓶頸點。

3.2Nova系統RPC.CALL以及RPC.CAST呼叫流程

    由前文可以看出,RPC.CALL是一種雙向通訊流程,即Worker程式接收訊息生產者生成的系統請求訊息,訊息消費者經過處理之後將系統相應結果反饋給Invoker程式。

    例如,一個使用者通過外部系統將“啟動虛擬機器”的需求傳送給NOVA-API,此時NOVA-API作為訊息生產者,將該訊息包裝為AMQP資訊以RPC.CALL方式通過Topic交換器轉發至點對點訊息佇列,此時,Nova-Compute作為訊息消費者,接收該資訊並通過底層虛擬化軟體執行相應虛擬機器的啟動程序;待使用者虛擬機器成功啟動之後,Nova-Compute作為訊息生產者通過Direct交換器和響應的訊息佇列將“虛擬機器啟動成功”響應訊息反饋給Nova-API,此時Nova-API作為訊息消費者接收該訊息並通知使用者虛擬機器啟動成功,一次完整的虛擬機器啟動的RPC.CALL呼叫流程結束。其具體流程如圖所示:

   
    (1)Invoker端生成一個Topic訊息生產者和一個Direct訊息消費者。其中,Topic訊息生產者傳送系統請求訊息到Topic交換器;Direct訊息消費者等待響應訊息。
    (2)Topic交換器根據訊息的Routing Key轉發訊息,Topic消費者從相應的訊息佇列中接收訊息,並傳遞給負責執行相關任務的Worker。

    (3)Worker根據請求訊息執行完任務之後,分配一個Direct訊息生產者,Direct訊息生產者將響應訊息傳送到Direct交換器。

    (4)Direct交換器根據響應訊息的Routing Key轉發至相應的訊息佇列,Direct消費者接收並把它傳遞給Invoker。

    RPC.CAST的遠端呼叫流程與RPC.CALL類似,只是缺少了系統訊息響應流程。一個Topic訊息生產者傳送系統請求訊息到Topic交換器,Topic交換器根據訊息的Routing Key將訊息轉發至共享訊息佇列,與共享訊息佇列相連的所有Topic消費者接收該系統請求訊息,並把它傳遞給響應的Worker進行處理,其呼叫流程如圖所示: