NOVA源碼分析——NOVA中的RabbitMQ解析

 本篇文章是由本人閱讀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進行處理,其調用流程如圖所示:

相關文章
相關標籤/搜索