Neutron-server的啟動(dòng)流程和工作方式(一)

導(dǎo)讀:

  • 啟動(dòng)機(jī)制
  • Entry point
  • 和Eventlet的交互
  • server的啟動(dòng)過(guò)程源代碼分析
  • wsgi app詳細(xì)分析

閱讀本文前首先要明白neutron-server是什么,作用是什么?

neutron-server是neutron的核心組件之一,負(fù)責(zé)直接接受外部請(qǐng)求(包括CLI API,REST API等),然后調(diào)度后端相應(yīng)的plugin進(jìn)行處理。

啟動(dòng)機(jī)制

neutron-server的本質(zhì)是一個(gè)Python Web Server Gateway Interface(WSGI),是通過(guò)eventlet lib來(lái)實(shí)現(xiàn)服務(wù)的異步并發(fā)模型的。實(shí)際工作時(shí),通過(guò)'serve_wsgi'啟動(dòng)點(diǎn)(Entry point)來(lái)構(gòu)造了一個(gè)NeutronApiService實(shí)例,通過(guò)該實(shí)例生成Eventlet,Greenpool來(lái)運(yùn)行WSGI app并回應(yīng)客戶端請(qǐng)求。
研究之前,首先需要先了解下Entry point的概念。

Entry point

neutron的所有服務(wù)(services)的啟動(dòng)點(diǎn)都定義在setup.cfg的"console_scripts"小節(jié)中,這些啟動(dòng)點(diǎn)直接指向各個(gè)服務(wù)的main()函數(shù),這些函數(shù)實(shí)際位于neutron/cmd/...目錄下。
代碼如下:

 43 [entry_points]
 44 console_scripts =
 45     neutron-db-manage = neutron.db.migration.cli:main
 46     neutron-debug = neutron.debug.shell:main
 47     neutron-dhcp-agent = neutron.cmd.eventlet.agents.dhcp:main
 48     neutron-keepalived-state-change = neutron.cmd.keepalived_state_change:main
 49     neutron-ipset-cleanup = neutron.cmd.ipset_cleanup:main
 50     neutron-l3-agent = neutron.cmd.eventlet.agents.l3:main
 51     neutron-linuxbridge-agent = neutron.cmd.eventlet.plugins.linuxbridge_neutron_agent:main
 52     neutron-linuxbridge-cleanup = neutron.cmd.linuxbridge_cleanup:main
 53     neutron-macvtap-agent = neutron.cmd.eventlet.plugins.macvtap_neutron_agent:main
 54     neutron-metadata-agent = neutron.cmd.eventlet.agents.metadata:main
 55     neutron-netns-cleanup = neutron.cmd.netns_cleanup:main
 56     neutron-openvswitch-agent = neutron.cmd.eventlet.plugins.ovs_neutron_agent:main
 57     neutron-ovs-cleanup = neutron.cmd.ovs_cleanup:main
 58     neutron-pd-notify = neutron.cmd.pd_notify:main
 59     neutron-server = neutron.cmd.eventlet.server:main#重點(diǎn)關(guān)注下這個(gè)main函數(shù)
 ...

和Eventlet的交互

如果一個(gè)service使用eventlet lib,服務(wù)本身不用直接調(diào)用eventlet.monkey_patch()函數(shù),只需要把相應(yīng)main()函數(shù)放到neutron/cmd/eventlet/...目錄下。這樣,Eventlet lib啟動(dòng)時(shí),會(huì)自動(dòng)啟動(dòng)各個(gè)服務(wù)。

server的啟動(dòng)過(guò)程源代碼分析

通過(guò)前面一小節(jié)的分析,下面重點(diǎn)關(guān)注neutron.cmd.eventlet.server:main()函數(shù):

 13 from neutron import server 
 14 from neutron.server import rpc_eventlet
 15 from neutron.server import wsgi_eventlet
 16   
 17   
 18 def main():                
 19     server.boot_server(wsgi_eventlet.eventlet_wsgi_server)
 20   
 21     
 22 def main_rpc_eventlet():   
 23     server.boot_server(rpc_eventlet.eventlet_rpc_server)

main函數(shù)中主要是調(diào)用了wsgi_eventlet.eventlet_wsgi_server()函數(shù):

 24 def eventlet_wsgi_server():
 25     neutron_api = service.serve_wsgi(service.NeutronApiService)
 26     start_api_and_rpc_workers(neutron_api)
 27   
 28       
 29 def start_api_and_rpc_workers(neutron_api):
 30     try:
 31         worker_launcher = service.start_all_workers()
 32 
 33         pool = eventlet.GreenPool()     
 34         api_thread = pool.spawn(neutron_api.wait)
 35         plugin_workers_thread = pool.spawn(worker_launcher.wait)
 36   
 37         # api and other workers should die together. When one dies,
 38         # kill the other.  
 39         api_thread.link(lambda gt: plugin_workers_thread.kill())
 40         plugin_workers_thread.link(lambda gt: api_thread.kill())
 41   
 42         pool.waitall()     
 43     except NotImplementedError:
 44         LOG.info(_LI("RPC was already started in parent process by "
 45                      "plugin."))                     
 46 
 47         neutron_api.wait() 

這個(gè)函數(shù)通過(guò)serve_wsgi()啟動(dòng)了一個(gè)wsgi服務(wù),該服務(wù)的啟動(dòng)分析(主要是啟動(dòng)neutron.api.v2.base的Controller)下一節(jié)詳細(xì)介紹。同時(shí)創(chuàng)建一個(gè)GreenPool,從線程池中生成一個(gè)api_thread用來(lái)監(jiān)聽api命令,當(dāng)命令到達(dá)時(shí),通過(guò)wsgi服務(wù)路由到neutron.api.v2.base中的Controller中去處理;
另外還生成一個(gè)或多個(gè)plugin_workers_thread,這個(gè)線程和rpc works關(guān)聯(lián),并監(jiān)聽topics中的消息隊(duì)列的請(qǐng)求,完成neutron內(nèi)部組件之間的通信。

wsgi app詳細(xì)分析

先來(lái)看看serve_wsgi()函數(shù):

 83 def serve_wsgi(cls):
 84 
 85     try:
 86         service = cls.create()
 87         service.start()
 88     except Exception:
 89         with excutils.save_and_reraise_exception():
 90             LOG.exception(_LE('Unrecoverable error: please check log '
 91                               'for details.'))
 92 
 93     registry.notify(resources.PROCESS, events.BEFORE_SPAWN, service)
 94     return service

該函數(shù)首先通過(guò)函數(shù)入?yún)?chuàng)建了一個(gè)service,并調(diào)用start方法啟動(dòng)該服務(wù)。我們接下來(lái)重點(diǎn)關(guān)注下函數(shù)的入?yún)㈩?,即NeutronApiService:

 49 class WsgiService(object):
 50     """Base class for WSGI based services.                                                          
 51 
 52     For each api you define, you must also define these flags:
 53     :<api>_listen: The address on which to listen
 54     :<api>_listen_port: The port on which to listen
 55 
 56     """
 57 
 58     def __init__(self, app_name):
 59         self.app_name = app_name
 60         self.wsgi_app = None
 61 
 62     def start(self):
 63         self.wsgi_app = _run_wsgi(self.app_name)
 64 
 65     def wait(self):
 66         self.wsgi_app.wait()
 67 
 68
 69 class NeutronApiService(WsgiService):
 70     """Class for neutron-api service."""
 71     def __init__(self, app_name):
 72         profiler.setup('neutron-server', cfg.CONF.host)
 73         super(NeutronApiService, self).__init__(app_name)
 74 
 75     @classmethod
 76     def create(cls, app_name='neutron'):
 77         # Setup logging early
 78         config.setup_logging()
 79         service = cls(app_name)
 80         return service

在start方法中調(diào)用_run_wsgi():

287 def _run_wsgi(app_name):
288     app = config.load_paste_app(app_name)
289     if not app:
290         LOG.error(_LE('No known API applications configured.'))
291         return
292     return run_wsgi_app(app)
293 
294 
295 def run_wsgi_app(app):
296     server = wsgi.Server("Neutron")
297     server.start(app, cfg.CONF.bind_port, cfg.CONF.bind_host,
298                  workers=_get_api_workers())
299     LOG.info(_LI("Neutron service started, listening on %(host)s:%(port)s"),
300              {'host': cfg.CONF.bind_host, 'port': cfg.CONF.bind_port})
301     return server

通過(guò)調(diào)用load_paste_app()函數(shù)生成app,并調(diào)用run_wsgi_app()函數(shù)來(lái)啟動(dòng)app:

126 def load_paste_app(app_name):
127     """Builds and returns a WSGI app from a paste config file.
128 
129     :param app_name: Name of the application to load
130     """
131     loader = wsgi.Loader(cfg.CONF)
132     app = loader.load_app(app_name)                                                                 
133     return app

從注釋可以了解到,該函數(shù)從配置文件構(gòu)造并返回一個(gè)WSGI app。通過(guò)跟蹤,該配置文件主要是/usr/share/neutron/api-paste.ini, server通過(guò)解析該文件來(lái)進(jìn)行指定WSGI app的實(shí)現(xiàn)。 在方法load_app中,調(diào)用paste的模塊庫(kù)deploy來(lái)實(shí)現(xiàn)對(duì)api_paste.ini中配置信息的解析和app的實(shí)現(xiàn)。

【注】:PasteDeployment是一種機(jī)制或者說(shuō)是一種設(shè)計(jì)模式,它用于在應(yīng)用WSGI Application和Server提供一個(gè)聯(lián)系的橋梁,并且為用戶提供一個(gè)接口,當(dāng)配置好PasteDeployment之后,用戶只需調(diào)用loadapp方法就可以使用現(xiàn)有的WSGI Application,而保持了WSGIApplication對(duì)用戶的透明性。

先了解下該文件的內(nèi)容及格式:

  1 [composite:neutron]                                                                                 
  2 use = egg:Paste#urlmap
  3 /: neutronversions_composite
  4 /v2.0: neutronapi_v2_0
  5 
  6 [composite:neutronapi_v2_0]
  7 use = call:neutron.auth:pipeline_factory
  8 noauth = cors http_proxy_to_wsgi request_id catch_errors extensions neutronapiapp_v2_0
  9 keystone = cors http_proxy_to_wsgi request_id catch_errors authtoken keystonecontext extensions neut    ronapiapp_v2_0
  ...
 32 [filter:authtoken]
 33 paste.filter_factory = keystonemiddleware.auth_token:filter_factory
 34 
 35 [filter:extensions]
 36 paste.filter_factory = neutron.api.extensions:plugin_aware_extension_middleware_factory
 37 
 38 [app:neutronversions]
 39 paste.app_factory = neutron.api.versions:Versions.factory
 40 
 41 [app:neutronapiapp_v2_0]
 42 paste.app_factory = neutron.api.v2.router:APIRouter.factory

這個(gè)文件主要是定義了WSGI app的實(shí)現(xiàn)以及路由方式。最終調(diào)用了neutronapiapp_v2_0的實(shí)現(xiàn),具體就是neutron.api.v2.router:APIRouter.factory,通過(guò)實(shí)例化APIRouter類實(shí)現(xiàn)app功能的擴(kuò)展和加載過(guò)程,該實(shí)例會(huì)將Neutorn資源(例如Ports,Networks,Subnets)和URL、controller來(lái)進(jìn)行一一映射。
關(guān)于APIRouter部分的實(shí)現(xiàn)下一節(jié)在繼續(xù)展開研究。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容