导读:
启动机制
Entry point
和Eventlet的交互
server的启动过程源代码分析
wsgi app详细分析
阅读本文前首先要明白neutron-server是什么,作用是什么?
neutron-server是neutron的核心组件之一,负责直接接受外部请求(包括CLI API,REST API等),然后调度后端相应的plugin进行处理。
启动机制
neutron-server的本质是一个Python Web Server Gateway Interface(WSGI),是通过eventlet lib来实现服务的异步并发模型的。实际工作时,通过'serve_wsgi'启动点(Entry point)来构造了一个NeutronApiService实例,通过该实例生成Eventlet,Greenpool来运行WSGI app并回应客户端请求。
研究之前,首先需要先了解下Entry point的概念。
Entry point
neutron的所有服务(services)的启动点都定义在setup.cfg的"console_scripts"小节中,这些启动点直接指向各个服务的main()函数,这些函数实际位于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#重点关注下这个main函数 ...
和Eventlet的交互
如果一个service使用eventlet lib,服务本身不用直接调用eventlet.monkey_patch()函数,只需要把相应main()函数放到neutron/cmd/eventlet/...目录下。这样,Eventlet lib启动时,会自动启动各个服务。
server的启动过程源代码分析
通过前面一小节的分析,下面重点关注neutron.cmd.eventlet.server:main()函数:
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函数中主要是调用了wsgi_eventlet.eventlet_wsgi_server()函数:
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()
这个函数通过serve_wsgi()启动了一个wsgi服务,该服务的启动分析(主要是启动neutron.api.v2.base的Controller)下一节详细介绍。同时创建一个GreenPool,从线程池中生成一个api_thread用来监听api命令,当命令到达时,通过wsgi服务路由到neutron.api.v2.base中的Controller中去处理;
另外还生成一个或多个plugin_workers_thread,这个线程和rpc works关联,并监听topics中的消息队列的请求,完成neutron内部组件之间的通信。
wsgi app详细分析
先来看看serve_wsgi()函数:
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
该函数首先通过函数入参创建了一个service,并调用start方法启动该服务。我们接下来重点关注下函数的入参类,即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方法中调用_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 return292 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
通过调用load_paste_app()函数生成app,并调用run_wsgi_app()函数来启动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
从注释可以了解到,该函数从配置文件构造并返回一个WSGI app。通过跟踪,该配置文件主要是/usr/share/neutron/api-paste.ini
, server通过解析该文件来进行指定WSGI app的实现。 在方法load_app中,调用paste的模块库deploy来实现对api_paste.ini中配置信息的解析和app的实现。
【注】:PasteDeployment是一种机制或者说是一种设计模式,它用于在应用WSGI Application和Server提供一个联系的桥梁,并且为用户提供一个接口,当配置好PasteDeployment之后,用户只需调用loadapp方法就可以使用现有的WSGI Application,而保持了WSGIApplication对用户的透明性。
先了解下该文件的内容及格式:
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
这个文件主要是定义了WSGI app的实现以及路由方式。最终调用了neutronapiapp_v2_0的实现,具体就是neutron.api.v2.router:APIRouter.factory,通过实例化APIRouter类实现app功能的扩展和加载过程,该实例会将Neutorn资源(例如Ports,Networks,Subnets)和URL、controller来进行一一映射。
关于APIRouter部分的实现下一节在继续展开研究。
作者:分享放大价值
链接:https://www.jianshu.com/p/586646d7500f
共同學習,寫下你的評論
評論加載中...
作者其他優質文章