nova-api代码分析(3)
2014-08-13 16:01
253 查看
nova-api代码分析,我们继续分析WSGIService的代码。
wsgi.Server用来初始化WSGI Server
到此server = service.WSGIService(api, use_ssl=should_use_ssl)启动WSGIService已经完成,
下面继续分析launcher.launch_service(server, workers=server.workers or 1)
执行launcher.wait()方法:
class WSGIService(object): """Provides ability to launch API from a 'paste' configuration.""" #WSGIService的初始化方法 def __init__(self, name, loader=None, use_ssl=False, max_url_len 4000 =None): """Initialize, but do not start the WSGI server. :param name: The name of the WSGI server given to the loader. :param loader: Loads the WSGI application using the given name. :returns: None """ self.name = name self.manager = self._get_manager() #初始化WSGI loader实例 self.loader = loader or wsgi.Loader() #调用load_app方法加载paste配置文件 self.app = self.loader.load_app(name) #获取主机名 self.host = getattr(CONF, '%s_listen' % name, "0.0.0.0") #获取端口号 self.port = getattr(CONF, '%s_listen_port' % name, 0) #获取worker进程数 self.workers = (getattr(CONF, '%s_workers' % name, None) or processutils.get_worker_count()) if self.workers and self.workers < 1: worker_name = '%s_workers' % name msg = (_("%(worker_name)s value of %(workers)s is invalid, " "must be greater than 0") % {'worker_name': worker_name, 'workers': str(self.workers)}) raise exception.InvalidInput(msg) self.use_ssl = use_ssl #初始化Server self.server = wsgi.Server(name, self.app, host=self.host, port=self.port, use_ssl=self.use_ssl, max_url_len=max_url_len) # Pull back actual port used self.port = self.server.port self.backdoor_port = None
wsgi.Server用来初始化WSGI Server
class Server(object): """Server class to manage a WSGI server, serving a WSGI application.""" #设定默认池大小,初始化为1000 default_pool_size = CONF.wsgi_default_pool_size def __init__(self, name, app, host='0.0.0.0', port=0, pool_size=None, protocol=eventlet.wsgi.HttpProtocol, backlog=128, use_ssl=False, max_url_len=None): """Initialize, but do not start, a WSGI server. :param name: Pretty name for logging. :param app: The WSGI application to serve. :param host: IP address to serve the application. :param port: Port number to server the application. :param pool_size: Maximum number of eventlets to spawn concurrently. :param backlog: Maximum number of queued connections. :param max_url_len: Maximum length of permitted URLs. :returns: None :raises: nova.exception.InvalidInput """ # Allow operators to customize http requests max header line size. eventlet.wsgi.MAX_HEADER_LINE = CONF.max_header_line self.name = name self.app = app self._server = None self._protocol = protocol self.pool_size = pool_size or self.default_pool_size #定义eventlet绿色线程池,默认大小1000线程 self._pool = eventlet.GreenPool(self.pool_size) self._logger = logging.getLogger("nova.%s.wsgi.server" % self.name) self._wsgi_logger = logging.WritableLogger(self._logger) self._use_ssl = use_ssl self._max_url_len = max_url_len if backlog < 1: raise exception.InvalidInput( reason='The backlog must be more than 1') bind_addr = (host, port) # TODO(dims): eventlet's green dns/socket module does not actually # support IPv6 in getaddrinfo(). We need to get around this in the # future or monitor upstream for a fix try: #返回socket连接信息信息字典<tt class="docutils literal"><span class="pre">(family,</span> <span class="pre">socktype,</span> <span class="pre">proto,</span> <span class="pre">canonname,</span> <span class="pre">sockaddr)</span></tt> info = socket.getaddrinfo(bind_addr[0], bind_addr[1], socket.AF_UNSPEC, socket.SOCK_STREAM)[0] family = info[0] bind_addr = info[-1] except Exception: family = socket.AF_INET try: #打开协程eventlet.listen监听端口 self._socket = eventlet.listen(bind_addr, family, backlog=backlog) except EnvironmentError: LOG.error(_("Could not bind to %(host)s:%(port)s"), {'host': host, 'port': port}) raise #获取主机和端口信息 (self.host, self.port) = self._socket.getsockname()[0:2] LOG.info(_("%(name)s listening on %(host)s:%(port)s") % self.__dict__)
到此server = service.WSGIService(api, use_ssl=should_use_ssl)启动WSGIService已经完成,
下面继续分析launcher.launch_service(server, workers=server.workers or 1)
def launch_service(self, service, workers=1): #service wrapper包装类 wrap = ServiceWrapper(service, workers) LOG.info(_LI('Starting %d workers'), wrap.workers) while self.running and len(wrap.children) < wrap.workers: #启动子进程 self._start_child(wrap)
class ServiceWrapper(object): def __init__(self, service, workers): #WSGI Service self.service = service #workers工作进程 self.workers = workers #子进程 self.children = set() #记录fork进程的时间 self.forktimes = []
def _start_child(self, wrap): if len(wrap.forktimes) > wrap.workers: # Limit ourselves to one process a second (over the period of # number of workers * 1 second). This will allow workers to # start up quickly but ensure we don't fork off children that # die instantly too quickly. if time.time() - wrap.forktimes[0] < wrap.workers: LOG.info(_LI('Forking too fast, sleeping')) time.sleep(1) wrap.forktimes.pop(0) #记录fork进程时间 wrap.forktimes.append(time.time()) #fork进程 pid = os.fork() #pid等于0进入到子进程里 if pid == 0: launcher = self._child_process(wrap.service) while True: self._child_process_handle_signal() status, signo = self._child_wait_for_exit_or_signal(launcher) if not _is_sighup_and_daemon(signo): break launcher.restart() os._exit(status) LOG.info(_LI('Started child %d'), pid) wrap.children.add(pid) self.children[pid] = wrap return pid
执行launcher.wait()方法:
def wait(self): """Loop waiting on children to die and respawning as necessary.""" LOG.debug('Full set of CONF:') CONF.log_opt_values(LOG, std_logging.DEBUG) try: while True: self.handle_signal() self._respawn_children() if self.sigcaught: signame = _signo_to_signame(self.sigcaught) LOG.info(_LI('Caught %s, stopping children'), signame) if not _is_sighup_and_daemon(self.sigcaught): break for pid in self.children: os.kill(pid, signal.SIGHUP) self.running = True self.sigcaught = None except eventlet.greenlet.GreenletExit: LOG.info(_LI("Wait called after thread killed. Cleaning up.")) for pid in self.children: try: os.kill(pid, signal.SIGTERM) except OSError as exc: if exc.errno != errno.ESRCH: raise # Wait for children to die if self.children: LOG.info(_LI('Waiting on %d children to exit'), len(self.children)) while self.children: self._wait_child()
相关文章推荐
- nova-api代码分析(1)
- nova-api代码分析(2)
- API Demo Snake代码分析一 FrameLayout新的认识
- API Demo SearchableDictionary代码分析二
- nova-api源码分析(APP中用到的开源库)
- Tripleo之nova-compute 和Ironic的代码深入分析(四)
- Tripleo之nova-compute 和Ironic的代码深入分析(一)
- Radmin的抓屏和显屏API代码部分分析
- novaclient代码解析之---通过nova show <server-id>命令解析Nova client与Nova API之间的调用关系
- JQuery data API实现代码分析
- JQuery html API支持解析执行Javascript脚本功能实现-代码分析
- openstack之nova-api服务流程分析
- openstack nova 源码分析2之nova-api,nova-compute
- openstack nova 源码分析2之nova-api,nova-compute
- nova-api源码分析(WSGI server的创建及启动)
- OpenStack 之 nova-api 的代码结构图
- API Demo Snake代码分析三 程序架构的分析
- DIOCP开源项目 API代码的封装和流程分析
- nova boot from volume代码分析
- Tripleo之nova-compute 和Ironic的代码深入分析(三)