[OpenStack Icehouse] 消息處理架構(gòu)Oslo/Messaging

文章裝載自:http://blog.csdn.net/juvxiao/article/details/23532617

在Icehouse中, rpc消息隊(duì)列相關(guān)處理從OpenStack.common.rpc慢慢的都轉(zhuǎn)移到oslo.messaging上, 現(xiàn)在僅有幾個(gè)項(xiàng)目沒(méi)有轉(zhuǎn)移, 將來(lái)也會(huì)轉(zhuǎn), 這個(gè)架構(gòu)更合理, 代碼結(jié)構(gòu)清晰, 且弱耦合.

本文章主要針對(duì)rpc, notify基本沒(méi)涉及, 有時(shí)間總結(jié)總結(jié).

基本概念

Server: 為各個(gè)Client提供RPC接口,它是消息的最終處理者;

Client: RPC接口的調(diào)用端, 我們常見(jiàn)的cast和call方法就是在這端調(diào)用;

Exchange: 理解為一個(gè)消息交換機(jī), 把消息分類,告訴何種路由到何種queue;

Topic: 是一個(gè)RPC消息的唯一標(biāo)識(shí); servers監(jiān)聽(tīng)這個(gè)topic的消息; client負(fù)責(zé)發(fā)出這個(gè)topic的消息;

Namespace: servers可以在一個(gè)topic上,提供多種方法集合, 這些方法集合通過(guò)namespace來(lái)分開(kāi)管理;

Method: 這個(gè)慨念很簡(jiǎn)單, 就是函數(shù), 即遠(yuǎn)程方法調(diào)用中的方法;

API version: 也就是server上提供的RPC api接口集合的版本號(hào),openstack中1.0起步, servers可以一次提供多種api version,client每次請(qǐng)求時(shí)只需描述它所需要的最低version就ok;

Transport: 可以理解為傳輸載體,這個(gè)很好理解, 就是我們使用的消息隊(duì)列中間件RabbitMQ, Qpid, ZeroMQ等等, 是負(fù)責(zé)整個(gè)消息處理的系統(tǒng), 它負(fù)責(zé)消息傳輸直到提供給clients返回, 使用此系統(tǒng)者, 不用了解細(xì)節(jié),? Openstack中實(shí)現(xiàn)的主要有這三種, AMQP標(biāo)準(zhǔn)下的rabbitMQ和Qpid, 和非AMQP的ZeroMQ, ZeroMQ更底層, 速度更快, 據(jù)說(shuō)快10倍。

Target這是個(gè)很重要的概念, 它描述了信息的處理方式, 該發(fā)哪里去(server屬性)和消息處理端(server)監(jiān)聽(tīng)什么信息(topic 屬性)。以下是Target的屬性

exchange (defaults to CONF.control_exchange)

topic

server (optional) 它會(huì)使server的標(biāo)示, 如host or host@backend 等等

fanout (defaults to False)這種模式類似于廣播, 符合條件的server都要監(jiān)聽(tīng)并做處理

namespace (optional)

API version (optional)

Use Cases [OpenStack中使用場(chǎng)景]

1.存在多個(gè)接口版本的server, 隨機(jī)選擇一個(gè)處理遠(yuǎn)程調(diào)用的方法

比如我們有多個(gè)接口版本的servers在監(jiān)聽(tīng)某個(gè)exchange上某個(gè)topic的方法調(diào)用, 一旦方法調(diào)用, 就會(huì)隨機(jī)選擇一個(gè)版本的server來(lái)監(jiān)聽(tīng)。

nova-api 調(diào)用'nova' exchange上 topic為'scheduler' 的'run_instance'方法, 然后,會(huì)有一個(gè)‘nova-scheduler’服務(wù)捕獲請(qǐng)求

2.存在多個(gè)接口版本的server, 特定server處理遠(yuǎn)程調(diào)用的方法

比如我們有多種接口版本的servers在監(jiān)聽(tīng)某個(gè)exchange上某個(gè)topic的方法調(diào)用, 不同于之前的是, 它要求選擇一個(gè)特定版本的server來(lái)監(jiān)聽(tīng)。

nova-scheduler 選擇 'foobar' host去運(yùn)行一個(gè)instance,那么就調(diào)用'nova' exchange上 topic為'scheduler' 的'run_instance'方法, 它同時(shí)指定要在“foobar”這個(gè)server上run

3.存在多個(gè)接口版本的server, 每個(gè)server都要處理遠(yuǎn)程調(diào)用的方法, 即所謂的fanout

比如我們有多種接口版本的servers在監(jiān)聽(tīng)某個(gè)exchange上某個(gè)topic的方法調(diào)用, 不同于之前的是, 它要求每個(gè)server都要監(jiān)聽(tīng)并運(yùn)行這個(gè)方法。

nova-compute 周期性的在faout模式調(diào)用 'update_service_capabilities' 方法, topic為 'scheduler',exchange為'nova' , 這樣每個(gè)nova-scheduler 服務(wù)都要捕獲并處理它

對(duì)象關(guān)系圖

Server端:消息隊(duì)列的監(jiān)聽(tīng)會(huì)在service啟動(dòng)的時(shí)候開(kāi)啟, 比如cinder-volume啟動(dòng)時(shí),會(huì)啟動(dòng)MessageHandlingServer( 下面具體介紹),來(lái)監(jiān)聽(tīng)消息并把消息dispatch到距離的Manager方法中做消息處理.

Client端: 負(fù)責(zé)消息發(fā)出,方法調(diào)用的code是在具體API中,如本例的VolumeAPI, 一般存放在rpcapi.py中.

為了進(jìn)行詳細(xì)解釋,先畫出整體的對(duì)象依賴圖:

消息處理端 [Server端]

MessageHandlingServer

這個(gè)就是server端,是消息的最終處理者。

Server端的實(shí)現(xiàn)有個(gè)兩個(gè)重要的內(nèi)部概念:dispatchers 和executors, dispatcher專注在消息的加載并調(diào)度到合適的方法。 executor是專注在怎樣從transport中獲得消息并把它分配給dispatcher的策略,是重開(kāi)一個(gè)線程還是在現(xiàn)有線程上繼續(xù)處理。實(shí)現(xiàn)dispatchers可以為rpc或者notification, executors可以為block或者eventlet

transport:消息中間件,rabbitMQ or Qpid or ZeroMQ

dispatcher:rpc或者notification

executor:block或者eventlet,默認(rèn)block, 它描述的是I/O策略,是重開(kāi)一個(gè)線程(EventletExecutor類實(shí)現(xiàn))還是在現(xiàn)有線程上繼續(xù)處理(BlockingExecutor實(shí)現(xiàn))。

MessageHandlingServer的start()方法開(kāi)始后 , 就會(huì)一直獲取消息隊(duì)列中信息,并把消息分配給dispatcher, 直到stop()方法被調(diào)用。

RPCDispatcher

RPC消息調(diào)度器

MessageHandlingServer就依賴它完成從消息到具體處理消息的方法的調(diào)度。

它主要干了 兩件事

1) 它利用Transport類(Transport又利用AMQPDriverBase的listen()) 獲得監(jiān)聽(tīng)器, 并報(bào)告給Executor

[python]view plaincopy

deflisten(self,?target):

conn?=self._get_connection(pooled=False)

listener?=?AMQPListener(self,?conn)

conn.declare_topic_consumer(target.topic,?listener)

conn.declare_topic_consumer('%s.%s'%?(target.topic,?target.server),

listener)

conn.declare_fanout_consumer(target.topic,?listener)

returnlistener

以上代碼可以看到listener里做了什么, declare了三個(gè)consumer, topic, topic.host, fanout, 正好呼應(yīng)上面介紹的三種user case。關(guān)于consumer, 將會(huì)在另一遍博文(介紹amqp的publisher/consumer機(jī)制)中來(lái)介紹

2) 把監(jiān)聽(tīng)器poll出來(lái)的消息通過(guò)這個(gè)dispatcher傳到XXXManager中的具體處理方法上

關(guān)于connectionpool不詳細(xì)介紹了,它是與具體Transport的連接池。

消息發(fā)出端[Client端]

主要都寫在rpcapi.py 中, 本文以Cinder項(xiàng)目為例,講述delete_volume消息發(fā)出的過(guò)程。

[python]view plaincopy

classVolumeAPI(object):

BASE_RPC_API_VERSION?='1.0'

def__init__(self,?topic=None):

super(VolumeAPI,self).__init__()

target?=?messaging.Target(topic=CONF.volume_topic,

version=self.BASE_RPC_API_VERSION)

self.client?=?rpc.get_client(target,'1.15')

....

defdelete_volume(self,?ctxt,?volume,?unmanage_only=False):

cctxt?=self.client.prepare(server=volume['host'],?version='1.15')

cctxt.cast(ctxt,'delete_volume',

volume_id=volume['id'],

unmanage_only=unmanage_only)

RPCClient

負(fù)責(zé)通過(guò)消息隊(duì)列發(fā)消息到消息隊(duì)列中,兩種方法調(diào)用的方式:cast? & call。關(guān)于這兩種方法也將會(huì)在另一遍博文(介紹amqp的publisher/consumer機(jī)制)中來(lái)介紹

會(huì)利用Transport的send方法。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,923評(píng)論 18 139
  • cinder RPC 分析 [TOC] 我們都知道在Cinder內(nèi)部,各組件之間通訊是通過(guò)RPC api,比如c...
    笨手笨腳越閱讀 1,851評(píng)論 0 3
  • 第一章 OpenStack基礎(chǔ) OpenStack管理的資源及提供的服務(wù)OpenStack做為一個(gè)操作系統(tǒng),...
    sgt_tiger閱讀 13,048評(píng)論 4 72
  • 來(lái)源 RabbitMQ是用Erlang實(shí)現(xiàn)的一個(gè)高并發(fā)高可靠AMQP消息隊(duì)列服務(wù)器。支持消息的持久化、事務(wù)、擁塞控...
    jiangmo閱讀 10,406評(píng)論 2 34
  • 2017年4月11日 星期二 陰轉(zhuǎn)多云 下午5:28分 作者:玉立集 未來(lái)之門 大人們經(jīng)常說(shuō) 你們小孩家家的 ...
    玉立集閱讀 209評(píng)論 2 0