openstack學習之RPC服務實現分析

openstack中的服務主要有兩種:一種是rest服務,提供Rest API;一種RPC服務,提供RPC API。本文討論RPC服務的實現。Rest服務的實現在《openstack學習之各種API》有所涉及。

RPC服務其實就是一個RPC server,client(客戶)可以通過RPC API進行調用。以nova爲例,nova中的多數服務(service)都是一個RPC server。比如nova-conductor,nova-compute,nova-consoleauth,nova-scheduler...等

實現一個rpc server需要幾個部分:
1)啓動命令代碼
2)Service定義
3)Manager定義
4)功能實現代碼
其中1)2)3)屬於框架性代碼,每個rpc server的實現都差不多;4)和rpc server要實現的功能相關。

以nova爲例,來分析這些部分的實現。
nova.cmd package中定義了所有服務的啓動代碼,包括rpc server和rest api服務。api.py,api_ec2.py,api_metadata.py,api_os_compute.py是rest api服務。這個目錄中還包含了一些命令工具(utility command),如manage.py。讀者可自行查看。

rpc server的啓動代碼基本類似:
1)定義main
2) 加載配置文件
3) 配置log
4) 創建server對象
5)啓動service.

步驟4的代碼compute:
    server = service.Service.create(binary='nova-compute',
                                    topic=CONF.compute_topic,
                                    db_allowed=CONF.conductor.use_local)
步驟4的代碼schduler:
    server = service.Service.create(binary='nova-scheduler',
                                    topic=CONF.scheduler_topic)
步驟4的代碼conductor:
    server = service.Service.create(binary='nova-conductor',
                                    topic=CONF.conductor.topic,
                                    manager=CONF.conductor.manager)
步驟5的代碼,3者一致
    service.serve(server)
    service.wait()

Service對象
Service位於nova.service.py
該對象繼承於nova.openstack.common.service.py中的Service

__init__方法
初始化幾個重要的成員
        self.host = host
        self.binary = binary
        self.topic = topic
        self.manager_class_name = manager

參數有啓動命令提供。host如果沒有傳入,從配置文件讀取。host = CONF.host

start方法:
該方法用來啓動rpc server。
該方法的主要功能就是創建RPC隊列並綁定到exchang上。
        target = messaging.Target(topic=self.topic, server=self.host)
        endpoints = [
            self.manager,
            baserpc.BaseRPCAPI(self.manager.service_name, self.backdoor_port)
        ]
        endpoints.extend(self.manager.additional_endpoints)

target用來指定該rpc server監聽在哪些隊列上。
target指定了2個參數:topic和server。查看target代碼(olso.messaging: oslo.messaging.target.py)
    :param server: Clients can request that a message be directed to a specific
      server, rather than just one of a pool of servers listening on the topic.
    :param topic: A name which identifies the set of interfaces exposed by a
      server. Multiple servers may listen on a topic and messages will be
      dispatched to one of the servers in a round-robin fashion.

底層如何使用target創建RPC隊列並綁定到exchang上,可以查看代碼
transport._listen
  self._driver.listen(target)
amqpdriver.listen
  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)
從代碼中可以看到創建了3個隊列,這個3個系列用來實現《openstack學習之RPC》提到的3種RPC場景
隨機調用某server上的一個方法: 通過第一個隊列實現
調用某特定server上的一個方法: 通過第二個隊列實現,這個隊列通過server參數來唯一標識一個隊列
調用所有server上的一個方法:通過第三個隊列實現,exchange type爲fantout類型
關於隊列的概念可以參考另一篇博文《openstack學習之RPC》

endpoints用來定義該rpc server支持哪些API。
manager中部分方法其實就是RPC API的方法,比如ComputeManager中有reboot_instance,這個方法就是一個RPC API。

client調用RCP API時會給出topic,方法名,方法參數等信息。oslo.messaging中的RPCDispatch會根據這些信息將該請求直接轉化爲對manager的相應方法的調用,並將方法參數準備好。

還可以看到openstack會給每個rpc server加一個額外的API(BaseRPCAPI),這個API目前只有一個ping方法。openstack內部會用這個方法檢測一個服務是否已經啓動完畢,如果啓動完畢,就可以相應ping調用。

Service對象還提供了另外一個功能,定時任務。
            self.tg.add_dynamic_timer(self.periodic_tasks,
                                     initial_delay=initial_delay,
                                     periodic_interval_max=
                                        self.periodic_interval_max)
self.periodic_tasks會調用manager.periodic_tasks。

綜上,Service對象的核心功能就是創建監聽隊列,並將收到的消息轉化爲對manager對象的方法調用。每個openstack項目實現都有定義一個自己的Service對象(如nova.service.py,cinder.service.py,neutron.service.py),這些對象的代碼基本類似,相信後邊社區會對這些代碼進行重構。

Manager對象

如前所述,Manager對象其實就是RPC API的入口。每個RPC API最終會轉化爲對Manger相應方法的調用,這個方法就是該RPC API的最終實現。

每個服務都會有一個相應的Manager對象,因爲一般每個服務所提供的API都是不同的。每個服務的實現都會有一個相應的python package(文件系統中的目錄),如conductor,compute,consoleauth,scheduler等。每個package中又會有一個manager.py。這個manager.py就定義了這個服務的Manager對象。如compute.manager.py定義了ComputeManager。nova boot命令最終會調用這個對象中的run_instance方法。
要想進一步看懂Manager中的代碼,就需要對相應問題領域(problem domain,也就是我們常說的業務流程)比較熟悉了。ComputeManager是處理虛擬機生命週期的,我們要對虛擬機有了解,才能讀懂其中的代碼。

掌握了Service + Manager,基本上就瞭解了RPC server是如何工作的,學習openstack代碼就比較直觀了。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章