Neutron-server的启动流程和工作方式(一)
导读:
- 启动机制
- 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 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
通过调用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部分的实现下一节在继续展开研究。