探索 OpenStack 之(15):oslo.messaging 和 Cinder 中 MessageQueue 消息的發送和接收

前言:上一篇文章 只是 RabbitMQ 的科普,本文將仔細分析 Cinder 中 RabbitMQ 的各組件的使用、消息的發送和接收等。因爲各流程步驟不少,本文只會使用若干流程圖來加以闡述,儘可能作到圖文自解釋,不會添加很細的文字說明了。html

1. Cinder 中建立卷的端到端過程

該過程主要包括兩部分:git

第一部分即初始化部分:cinder-api 服務啓動過程當中 (參見另外一篇文章),APIRouter 類被初始化,接着它會初始化 VolumeController 類,最終,SchedulerAPI 類以及 VolumeAPI 類會被初始化,它們分別會調用 get_client 方法獲取一個 RPCClient 的實例,其中,target 即發送消息的目的 RabbitMQ exchange,它由 cinder.conf 定義。該 RPCClient 實例的方法會分別被 SchedulerAPI 類和 VolumeAPI類來發送。github

第二部分即流程處理部分:當 cinder-api 的 WSGI server 收到一個卷建立的請求後,APIRouter 會負責把該請求分發到 VolumeController 類的 create 方法 (其過程請參考另外一篇文章)。該方法會依次:json

(16)生成一個 task flow,其中的幾個 task 依次提取request中的數據、預留 Quota、在 db 中建立 entery、提交 quota,最後調用 VolumeCastTask::exectue 方法。api

(17)調用 SchedulerAPI 的 create_volume 方法,它會調用 RPCClient 的 cast 方法來發出一個建立volume 的 message。數組

(18 ~ 20)最終 SchedulerManager 的 create_volume 方法會被調用,它會執行 filtering 和 weighting 來選擇一個最優的 host。app

(23)肯定好該 host 後,調用 volume.API 的 create_volume 方法。dom

(24 ~ 25)該方法會調用 RPCClient 的 cast 方法發出一個 volume creation 消息給 cinder-volumeide

(26)最終,指定 host 上的 VolumeManager 的 create_volume 方法會被調用,它會調用 cinder driver 來建立 volume。spa

該過程顯示了 volume 建立過程當中,cinder 的三大組件 cinder-api、cinder-scheduler 和 cinder-volume 使用 RabbitMQ 來傳遞和接收消息來執行操做的過程。

2. 消息發送機制 (olso.messaging.RPCClient 的 cast 和 call 方法)

幾個要點:

(0)cast 方法把消息發出去就算了,不須要返回值;call 方法在消息發出後須要等待消息結果返回,所以它在發消息(步驟 27)以前,會建立一個 waiter (步驟26)來等待消息返回。

(3)get_transport 方法會使用 stevedore 庫來加載特定的 messaging driver 類,默認狀況下 conf.rpc_backend 的值爲 'rabbit', 所以其對應的 driver 類 oslo.messaging._drivers.impl_rabbit.RabbitDriver會被加載;而後生成一個 Transport 實例,該實例實際上只是 driver 實例的一個wrapper。

(6)初始化 Target 實例,它實際上代表了 message 的目的地,包括消息被髮往的地方或者一個應用須要監聽的對象。其屬性包括:      

def __init__(self, exchange=None, topic=None, namespace=None, version=None, server=None, fanout=None):
        self.exchange = exchange // MQ 的exchange,使用 cinder.conf 中的定義,默認是 control_exchange : openstack
        self.topic = topic //MQ 的 queue,由 cinder.conf 指定: scheduler_topic = cinder-scheduler,volume_topic = cinder-volume 
        self.namespace = namespace //消息處理類的方法集合,默認是 null
        self.version = version
        self.server = server //消息的特定目的consumer application,是 cinder 裏面的一個消息處理類
        self.fanout = fanout //一個flag,設置的話,消息將發給全部queue的consumers

(15 ~ 21) cast 方法的實現,最終是使用 RabbitMQ 將消息發出去

(20 ~ 35)call 方法的實現,在第 27 步將消息發出去以前先建立一個 waiter 來等待返回的消息,它等到返回的消息後會把結果傳回到caller。

 

 3. 消息接收和分發機制 (olso.messaging.RPCDispatcher)

 

 

(2~3)cinder-scheduler 和在各節點上的 cinder-volume 做爲 service 啓動的時候,會初始化並啓動一個RPC server,該 server 會監聽 message queu並分發消息。

(8,30)RPCDispatcher 負責爲接收到的 PRC message 調用一個 endpoint 類 的 method。

  • endpoint 類:
    • 對 cinder-scheduler 的 rpcapi 發送的消息來講,endpoint 是類 SchedulerManager;
    • 對 cinder-volume 的 rpcapi 發出的消息來講,endpoint 是類 VolumeManager。
  • endpoint 類的方法:被調用的方法名稱會在 cast 方法中做爲參數傳入,好比下面 create_volume 方法 cast 這個消息後,它會分發到 SchedulerManager 的 create_volume 方法。
//cinder/scheduler/rpcapi.py
def
create_volume(self, ctxt, topic, volume_id, snapshot_id=None, image_id=None, request_spec=None, filter_properties=None): cctxt = self.client.prepare(version='1.2') request_spec_p = jsonutils.to_primitive(request_spec) return cctxt.cast(ctxt, 'create_volume', topic=topic, volume_id=volume_id, snapshot_id=snapshot_id, image_id=image_id, request_spec=request_spec_p, filter_properties=filter_properties)

 (11,26 ~ 28)EventletExecutor 會初始化一個大小爲 conf.rpc_thread_pool_size 的線程池,它調用 AMQPListener 的 poll 方法獲取 message 後,會在一個線程中調用 RPCDispatcher 的 __call__ 方法來調用消息處理方法。

(20, 26)AMQPListener 會無限循環去獲取 message,直到它被中止。獲取到的 message 會被交給 EventletExecutor ,它會調用RCPDispatcher的方法將其分發給某個類的某個方法。

4. Cinder 所用到的 RabbitMQ 組件

注:有些組件,好比 cinder_scheduler.controller 尚不清楚其用途。

 5. 消息示例

5.1 每一個節點上的 cinder-volume 服務向 cinder-scheduler 服務更新其 capabilities 的消息

 

消息發送者 發送頻率 MQ exchange 消息接收者類 備註
每一個cinder-volume 節點上的cinder-volume 服務 1 分鐘 cinder-scheduler_fanout SchedulerManager::update_service_capabilities cinder-scheduler 的 HostManager 類維護一個數組service_states,每一個cinder-volume 節點佔該數組的一項,其值爲該節點上 cinder-volume 服務的 capabilities,該值經過消息機制按期更新。在發生特定操做好比刪除卷時,會進行馬上更新。

消息內容示例:

{u'_context_domain': None, u'_context_request_id': u'req-c0a0babc-3fec-41fe-ae6a-45418beec8fc', u'_context_quota_class': None, u'_context_service_catalog': [], u'_context_auth_token': '<SANITIZED>', u'_context_user': None, u'_context_user_id': None, u'_context_is_admin': True, u'version': u'1.0', u'_context_project_domain': None, u'_context_timestamp': u'2015-03-16T10:13:14.676590', u'method': u'update_service_capabilities', u'_context_remote_address': None, u'_context_roles': [u'admin'], u'args': {u'service_name': u'volume', u'host': u'network@lvmdriver-network', u'capabilities': {u'pools': [{u'pool_name': u'lvmbackend', u'QoS_support': False, u'allocated_capacity_gb': 4, u'free_capacity_gb': 0.36, u'location_info': u'LVMVolumeDriver:network:system:default:0', u'total_capacity_gb': 9.06, u'reserved_percentage': 0}], u'driver_version': u'2.0.0', u'vendor_name': u'Open Source', u'volume_backend_name': u'lvmbackend', u'storage_protocol': u'iSCSI'}}, u'_unique_id': u'f18ce7979c3148ce933ba93ee77e4f47', u'_context_project_name': None, u'_context_read_deleted': u'no', u'_context_user_identity': u'- - - - -', u'_context_tenant': None, u'_context_project_id': None, u'_context_user_domain': None}

 5.2 建立卷時 cinder-api 服務發給 cinder-scheduler 服務的消息

 
 
MQ Exchange: openstack
 
 
Message body:
{"oslo.message": "{"_context_domain": null, "_context_request_id": "req-7bb7ff5b-97e5-481a-97d4-c636b2e0687a", "_context_quota_class": null, "_context_service_catalog": [{"endpoints": [{"adminURL": "http://controller:8774/v2/43f66bb82e684bbe9eb9ef6892bd7fd6", "region": "regionOne", "id": "055951b654364d918aaa37bbe365906e", "internalURL": "hhttp://controller:8774/v2/43f66bb82e684bbe9eb9ef6892bd7fd6", "publicURL": "http://controller:8774/v2/43f66bb82e684bbe9eb9ef6892bd7fd6"}], "endpoints_links": [], "type": "compute", "name": "nova"}], "_context_auth_token": "PKIZ_...==", "_context_user_id": "1dc0db32a936496ebfc50be54924a7cc", "_context_is_admin": true, "version": "1.2", "_context_timestamp": "2015-03-21T07:26:33.337831", "_context_project_domain": null, "_context_user": "1dc0db32a936496ebfc50be54924a7cc", "method": "create_volume", "_context_remote_address": "192.168.1.20", "_context_roles": ["admin", "_member_"], "args": {"request_spec": {"source_replicaid": null, "volume_properties": {"status": "creating", "volume_type_id": null, "display_name": null, "volume_metadata": [], "volume_admin_metadata": [], "reservations": ["881c6dda-bf43-4535-952c-1c30ae24de9e", "b0949e21-f7e6-41ac-a8c1-8314e6b4a13d"], "display_description": null, "availability_zone": "az1", "attach_status": "detached", "source_volid": null, "metadata": {}, "source_replicaid": null, "encryption_key_id": null, "consistencygroup_id": null, "replication_status": "disabled", "snapshot_id": null, "user_id": "1dc0db32a936496ebfc50be54924a7cc", "project_id": "43f66bb82e684bbe9eb9ef6892bd7fd6", "id": "89dd8904-b893-42db-b158-7f14c13bf1cc", "size": 1}, "volume_type": {}, "image_id": null, "snapshot_id": null, "consistencygroup_id": null, "source_volid": null, "volume_id": "89dd8904-b893-42db-b158-7f14c13bf1cc"}, "volume_id": "89dd8904-b893-42db-b158-7f14c13bf1cc", "filter_properties": {}, "topic": "cinder-volume", "image_id": null, "snapshot_id": null}, "_unique_id": "73f2789be1124ac095909d7e4e542d8d", "_context_project_name": "admin", "_context_read_deleted": "no", "_context_user_identity": "1dc0db32a936496ebfc50be54924a7cc 43f66bb82e684bbe9eb9ef6892bd7fd6 - - -", "_context_tenant": "43f66bb82e684bbe9eb9ef6892bd7fd6", "_context_project_id": "43f66bb82e684bbe9eb9ef6892bd7fd6", "_context_user_domain": null}", "oslo.version": "2.0"}
Message routing_key: 'cinder-scheduler'
Endpoint method: SchedulerManager::create_volume

5.3 建立卷時 cinder-scheduler 服務發給某個節點上 cinder-volume 服務的消息

MQ Exchange: openstack
 
 
Message body:
'{"oslo.message": "{"_context_domain": null, "_context_request_id": "req-7bb7ff5b-97e5-481a-97d4-c636b2e0687a", "_context_quota_class": null, "_context_service_catalog": [{"endpoints": [{"adminURL": "http://controller:8774/v2/43f66bb82e684bbe9eb9ef6892bd7fd6", "region": "regionOne", "internalURL": "hhttp://controller:8774/v2/43f66bb82e684bbe9eb9ef6892bd7fd6", "id": "055951b654364d918aaa37bbe365906e", "publicURL": "http://controller:8774/v2/43f66bb82e684bbe9eb9ef6892bd7fd6"}], "endpoints_links": [], "type": "compute", "name": "nova"}], "_context_auth_token": "PKIZ_...==", "_context_user_id": "1dc0db32a936496ebfc50be54924a7cc", "_context_is_admin": true, "version": "1.4", "_context_timestamp": "2015-03-21T07:26:33.337831", "_context_project_domain": null, "_context_user": "1dc0db32a936496ebfc50be54924a7cc", "method": "create_volume", "_context_remote_address": "192.168.1.20", "_context_roles": ["admin", "_member_"], "args": {"request_spec": {"source_replicaid": null, "volume_properties": {"status": "creating", "volume_type_id": null, "display_name": null, "availability_zone": "az1", "consistencygroup_id": null, "reservations": ["881c6dda-bf43-4535-952c-1c30ae24de9e", "b0949e21-f7e6-41ac-a8c1-8314e6b4a13d"], "volume_admin_metadata": [], "attach_status": "detached", "display_description": null, "metadata": {}, "source_replicaid": null, "encryption_key_id": null, "volume_metadata": [], "replication_status": "disabled", "snapshot_id": null, "source_volid": null, "user_id": "1dc0db32a936496ebfc50be54924a7cc", "project_id": "43f66bb82e684bbe9eb9ef6892bd7fd6", "id": "89dd8904-b893-42db-b158-7f14c13bf1cc", "size": 1}, "volume_type": {}, "image_id": null, "snapshot_id": null, "consistencygroup_id": null, "source_volid": null, "volume_id": "89dd8904-b893-42db-b158-7f14c13bf1cc", "resource_properties": {"status": "creating", "volume_type_id": null, "user_id": "1dc0db32a936496ebfc50be54924a7cc", "volume_metadata": [], "volume_admin_metadata": [], "reservations": ["881c6dda-bf43-4535-952c-1c30ae24de9e", "b0949e21-f7e6-41ac-a8c1-8314e6b4a13d"], "display_description": null, "availability_zone": "az1", "attach_status": "detached", "source_volid": null, "metadata": {}, "source_replicaid": null, "encryption_key_id": null, "consistencygroup_id": null, "replication_status": "disabled", "snapshot_id": null, "display_name": null, "project_id": "43f66bb82e684bbe9eb9ef6892bd7fd6", "id": "89dd8904-b893-42db-b158-7f14c13bf1cc", "size": 1}}, "source_replicaid": null, "allow_reschedule": true, "filter_properties": {"config_options": {}, "availability_zone": "az1", "request_spec": {"volume_id": "89dd8904-b893-42db-b158-7f14c13bf1cc", "source_replicaid": null, "volume_properties": {"status": "creating", "volume_type_id": null, "display_name": null, "volume_metadata": [], "reservations": ["881c6dda-bf43-4535-952c-1c30ae24de9e", "b0949e21-f7e6-41ac-a8c1-8314e6b4a13d"], "availability_zone": "az1", "user_id": "1dc0db32a936496ebfc50be54924a7cc", "attach_status": "detached", "display_description": null, "id": "89dd8904-b893-42db-b158-7f14c13bf1cc", "replication_status": "disabled", "snapshot_id": null, "encryption_key_id": null, "source_volid": null, "volume_admin_metadata": [], "source_replicaid": null, "project_id": "43f66bb82e684bbe9eb9ef6892bd7fd6", "consistencygroup_id": null, "size": 1, "metadata": {}}, "volume_type": {}, "image_id": null, "consistencygroup_id": null, "source_volid": null, "snapshot_id": null, "resource_properties": {"status": "creating", "volume_type_id": null, "volume_metadata": [], "reservations": ["881c6dda-bf43-4535-952c-1c30ae24de9e", "b0949e21-f7e6-41ac-a8c1-8314e6b4a13d"], "source_volid": null, "consistencygroup_id": null, "replication_status": "disabled", "snapshot_id": null, "user_id": "1dc0db32a936496ebfc50be54924a7cc", "id": "89dd8904-b893-42db-b158-7f14c13bf1cc", "size": 1, "display_name": null, "source_replicaid": null, "availability_zone": "az1", "attach_status": "detached", "display_description": null, "encryption_key_id": null, "volume_admin_metadata": [], "project_id": "43f66bb82e684bbe9eb9ef6892bd7fd6", "metadata": {}}}, "qos_specs": null, "size": 1, "retry": {"num_attempts": 1, "hosts": ["block2@lvmdriver-b21#lvmbackend"]}, "user_id": "1dc0db32a936496ebfc50be54924a7cc", "volume_type": {}, "resource_type": {}, "metadata": {}}, "source_volid": null, "image_id": null, "snapshot_id": null, "consistencygroup_id": null, "volume_id": "89dd8904-b893-42db-b158-7f14c13bf1cc"}, "_unique_id": "e730b03f68cb426f906e39c64e265956", "_context_project_name": "admin", "_context_read_deleted": "no", "_context_user_identity": "1dc0db32a936496ebfc50be54924a7cc 43f66bb82e684bbe9eb9ef6892bd7fd6 - - -", "_context_tenant": "43f66bb82e684bbe9eb9ef6892bd7fd6", "_context_project_id": "43f66bb82e684bbe9eb9ef6892bd7fd6", "_context_user_domain": null}", "oslo.version": "2.0"}'
Message routing_key: 'cinder-volume.block2@lvmdriver-b21'
Endpoint method: VolumerManager::create_volume

 

5.4 刪除卷時 cinder-api 服務發給目的節點上 cinder-volume 服務的消息

MQ Exchange: openstack
Message body:
{"oslo.message": "{"_context_domain": null, "_context_request_id": "req-a5297b18-7b87-4ea1-914d-0174790a1ca5", "_context_quota_class": null, "_context_service_catalog": [{"endpoints_links": [], "endpoints": [{"adminURL": "http://controller:8774/v2/43f66bb82e684bbe9eb9ef6892bd7fd6", "region": "regionOne", "publicURL": "http://controller:8774/v2/43f66bb82e684bbe9eb9ef6892bd7fd6", "id": "055951b654364d918aaa37bbe365906e", "internalURL": "hhttp://controller:8774/v2/43f66bb82e684bbe9eb9ef6892bd7fd6"}], "type": "compute", "name": "nova"}], "_context_auth_token": "PKIZ_...", "_context_user_id": "1dc0db32a936496ebfc50be54924a7cc", "_context_is_admin": true, "version": "1.15", "_context_timestamp": "2015-03-21T07:16:02.443178", "_context_project_domain": null, "_context_user": "1dc0db32a936496ebfc50be54924a7cc", "method": "delete_volume", "_context_remote_address": "192.168.1.20", "_context_roles": ["admin", "_member_"], "args": {"unmanage_only": false, "volume_id": "a8a4bf9b-b233-4bd4-9ec4-d132d3b4b0af"}, "_unique_id": "370304cba81641ee82e8eaf84b519e25", "_context_project_name": "admin", "_context_read_deleted": "no", "_context_user_identity": "1dc0db32a936496ebfc50be54924a7cc 43f66bb82e684bbe9eb9ef6892bd7fd6 - - -", "_context_tenant": "43f66bb82e684bbe9eb9ef6892bd7fd6", "_context_project_id": "43f66bb82e684bbe9eb9ef6892bd7fd6", "_context_user_domain": null}", "oslo.version": "2.0"}

Message routing_key: 'cinder-volume.block2@lvmdriver-b21'
Endpoint method: VolumeManager::delete_volume
相關文章
相關標籤/搜索