Web Server启动方式有两种:
1 启动新的进程
2 在当前进程中以协程的方式启动
先看下面代码:
class Server(object):
def start(self, application, port, host='0.0.0.0', workers=0):
"""Run a WSGI server with the given application."""
self._host = host
self._port = port
backlog = CONF.backlog
self._socket = self._get_socket(self._host,
self._port,
backlog=backlog)
self._launch(application, workers)
def _launch(self, application, workers=0):
service = WorkerService(self, application, self.disable_ssl, workers)
if workers < 1:
# The API service should run in the current process.
self._server = service
# Dump the initial option values
cfg.CONF.log_opt_values(LOG, logging.DEBUG)
service.start()
systemd.notify_once()
else:
# dispose the whole pool before os.fork, otherwise there will
# be shared DB connections in child processes which may cause
# DB errors.
api.context_manager.dispose_pool()
# The API service runs in a number of child processes.
# Minimize the cost of checking for child exit by extending the
# wait interval past the default of 0.01s.
self._server = common_service.ProcessLauncher(cfg.CONF,
wait_interval=1.0)
self._server.launch_service(service,
workers=service.worker_process_count)
这段代码根据参数works来决定是在当前进程中还是另外启动新进程来启动Web Server。
一 参数works
参数works的数值能够决定如何启动一个Web Server,那么它是在哪里赋值的呢?请看下面代码:
def run_wsgi_app(app):
server = wsgi.Server("Neutron")
server.start(app, cfg.CONF.bind_port, cfg.CONF.bind_host,
workers=_get_api_workers())
LOG.info(_LI("Neutron service started, listening on %(host)s:%(port)s"),
{'host': cfg.CONF.bind_host, 'port': cfg.CONF.bind_port})
return server
def _get_api_workers():
workers = cfg.CONF.api_workers
if workers is None:
workers = processutils.get_worker_count()
return workers
可以看到,works这个参数是由配置文件配置的,如果配置文件没有配置的话,则以当前运行所在的Host/VM的CPU的核数为准。配置文件是neutron.conf,配置项如下:
#[etc/neutron.conf]
api_workers=n #n表示某个数值
api_workers数值的含义是:
当api_workers<1时,表示在当前进程启动Web Server。
当api_workers=n>=1时,表示要另外启动n个新进程,在这些新进程中再分别启动Web Server。
二 在当前进程启动Web Server
在当前进程中启动Web Server,对应的条件是worker<1,代码如下:
class Server(object):
def _launch(self, application, workers=0):
service = WorkerService(self, application, self.disable_ssl, workers)
if workers < 1:
# The API service should run in the current process.
self._server = service
# Dump the initial option values
cfg.CONF.log_opt_values(LOG, logging.DEBUG)
service.start()
systemd.notify_once()
else:
# dispose the whole pool before os.fork, otherwise there will
# be shared DB connections in child processes which may cause
# DB errors.
api.context_manager.dispose_pool()
# The API service runs in a number of child processes.
# Minimize the cost of checking for child exit by extending the
# wait interval past the default of 0.01s.
self._server = common_service.ProcessLauncher(cfg.CONF,
wait_interval=1.0)
self._server.launch_service(service,
workers=service.worker_process_count)
class WorkerService(neutron_worker.NeutronWorker):
def start(self):
super(WorkerService, self).start()
# When api worker is stopped it kills the eventlet wsgi server which
# internally closes the wsgi server socket object. This server socket
# object becomes not usable which leads to "Bad file descriptor"
# errors on service restart.
# Duplicate a socket object to keep a file descriptor usable.
dup_sock = self._service._socket.dup()
if CONF.use_ssl and not self._disable_ssl:
dup_sock = sslutils.wrap(CONF, dup_sock)
self._server = self._service.pool.spawn(self._service._run,
self._application,
dup_sock)
这里的self._service(WorkService._service)代表的就是Server实例。这几个参数的说明如下:
1 self._service.pool
就是Server实例的成员变量pool:
pool=eventlet.GreenPool(1)
2 self._service._run
就是Server实例的一个成员函数:
def _run(self, application, socket):
"""Start a WSGI server in a new green thread."""
eventlet.wsgi.server(socket, application,
max_size=self.num_threads,
log=LOG,
keepalive=CONF.wsgi_keep_alive,
log_format=CONF.wsgi_log_format,
socket_timeout=self.client_socket_timeout)
3 self._application
就是如下代码的load的application
def _run_wsgi(app_name):
app = config.load_paste_app(app_name)
if not app:
LOG.error(_LE('No known API applications configured.'))
return
return run_wsgi_app(app)
三 在新进程中启动Web Server
新启动进程,并在新的进程中启动Web Server,对应的条件是worker>=1,代码如下:
Class ProcessLauncher的代码位于oslo_service/service.py中,可以在github中搜索oslo_service找到对应代码。
代码脉络如下: