zoukankan      html  css  js  c++  java
  • nova-api源码分析(WSGI server的创建及启动)

    源码版本:H版

    一、前奏

           nova api本身作为一个WSGI服务器,对外提供HTTP请求服务,对内调用nova的其他模块响应相应的HTTP请求。分为两大部分,一是服务器本身的启动与运行,一是加载的app,这个用来处理请求。

       目录结构如下:

          

          首先,nova api是作为一个WSGI服务,肯定要查看它的启动过程,查看启动脚本/etc/init.d/openstack-nova-api(使用service命令实际在调用/etc/init.d文件夹下的脚本文件)。在/etc/init.d/openstack-nova-api文件中,start选项代表调用脚本/usr/bin/nova-api,如下:

     /usr/bin/nova-api

    import sys
    from nova.cmd.api import main
    if __name__ == "__main__":
      sys.exit(main())

    接着,分析如下:

    /nova/cmd/api.py (文件位置为/usr/lib/python2.6/site-packages,此处及下面均省略)

    def main():
        config.parse_args(sys.argv)
        logging.setup("nova")
        utils.monkey_patch()
    
        launcher = service.process_launcher()
        for api in CONF.enabled_apis:
            should_use_ssl = api in CONF.enabled_ssl_apis
            if api == 'ec2':
                """为了与ec2兼容"""
                server = service.WSGIService(api, use_ssl=should_use_ssl,
                                             max_url_len=16384) 
            else:
                server = service.WSGIService(api, use_ssl=should_use_ssl) 【1
            launcher.launch_service(server, workers=server.workers or 1)【2】
        """当前进程处于等待状态"""
      launcher.wait()

     二、分析【1】处:主要是WSGIService对象的创建

    /nova/service.py

    WSGIService类:
    def __init__(self, name, loader=None, use_ssl=False, max_url_len=None):
        self.name = name
        self.manager = self._get_manager()
        self.loader = loader or wsgi.Loader()
        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)
        self.workers = getattr(CONF, '%s_workers' % name, None)
        self.use_ssl = use_ssl
        """封装了wsgi.py中的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

    /nova/wsgi.py

    Loader类:
    def __init__(self, config_path=None):
      """试图寻找api-paste.ini配置文件"""
      self.config_path = None
    
      config_path = config_path or CONF.api_paste_config
      if not os.path.isabs(config_path):
        self.config_path = CONF.find_file(config_path)
      elif os.path.exists(config_path):
        self.config_path = config_path
    
      if not self.config_path:
        raise exception.ConfigNotFound(path=config_path)
    
    def load_app(self, name):
      try:
        LOG.debug("Loading app %(name)s from %(path)s",
                    {'name': name, 'path': self.config_path})
        return deploy.loadapp("config:%s" % self.config_path, name=name)
      except LookupError as err:
        LOG.error(err)
        raise exception.PasteAppNotFound(name=name, path=self.config_path)    

    (此处关于app的具体加载过程见后文。)

    三、分析【2】处:主要是WSGIService的启动

    /nova/openstack/common/service.py

    ProcessLauncher类:
    def launch_service(self, service, workers=1):
      wrap = ServiceWrapper(service, workers)
    
      LOG.info(_('Starting %d workers'), wrap.workers)
      """循环启动workers数目的子进程"""
      while self.running and len(wrap.children) < wrap.workers:
        self._start_child(wrap)
    
    def _start_child(self, wrap):
      ...
      """创建子进程"""
      pid = os.fork()
      if pid == 0:
                
        status = 0
        try:
          """子进程进行处理"""
          self._child_process(wrap.service)
        except SignalExit as exc:
          signame = {signal.SIGTERM: 'SIGTERM',
                        signal.SIGINT: 'SIGINT'}[exc.signo]
          LOG.info(_('Caught %s, exiting'), signame)
          status = exc.code
        except SystemExit as exc:
          status = exc.code
        except BaseException:
          LOG.exception(_('Unhandled exception'))
          status = 2
        finally:
          """出现异常停掉服务"""
          wrap.service.stop()
        """子进程退出"""
        os._exit(status)
    
      LOG.info(_('Started child %d'), pid)
      wrap.children.add(pid)
      self.children[pid] = wrap
      return pid
    
    
    
    def _child_process(self, service):
      ...
      launcher = Launcher()
      launcher.run_service(service)

    /nova/openstack/common/service.py

    Launcher类:
    def __init__(self):
        self._services = threadgroup.ThreadGroup()
        self.backdoor_port = eventlet_backdoor.initialize_if_enabled() 
    
    
    @staticmethod
    def run_service(service):
        service.start()
        service.wait()

    由于这里的service是WSGIService对象,如下:

    /nova/service.py

    WSGIService类:
    def start(self):
    if self.manager: self.manager.init_host() self.manager.pre_start_hook() if self.backdoor_port is not None: self.manager.backdoor_port = self.backdoor_port self.server.start() if self.manager: self.manager.post_start_hook() def wait(self): self.server.wait()

    /nova/wsgi.py

    Server类:
    def start(self):
        ...
        wsgi_kwargs = {
            'func': eventlet.wsgi.server,
            'sock': self._socket,
            'site': self.app,
            'protocol': self._protocol,
            'custom_pool': self._pool,
            'log': self._wsgi_logger,
            'log_format': CONF.wsgi_log_format
            }
    
        if self._max_url_len:
            wsgi_kwargs['url_length_limit'] = self._max_url_len
        """创建一个green thread,运行func函数,在其中传入后面的参数。此处为调用eventlet.wsgi.server函数,传入sock=self._socket等参数到server函数中。其中eventlet.wsgi.server函数负责启动一个wsgi服务器程序接受客户端发来的请求,
    可以参考:http://eventlet.net/doc/modules/wsgi.html?highlight=wsgi.server#eventlet.wsgi.server
    """ self._server = eventlet.spawn(**wsgi_kwargs) def wait(self): try: """green thread阻塞等待""" self._server.wait() except greenlet.GreenletExit: LOG.info(_("WSGI server has stopped."))

    总结:

          我们可以通过pstree命令查看系统中进程的子进程数,发现nova-api进程中有一个主进程,其子进程数目为一个ec2,一个metadata,有workers数目的osapi_compute(其中workers可以通过/etc/nova/nova.conf中osapi_compute_workers选项设置)。然后通过ps –Lf查看每个进程的线程数目,发现其均为单线程。由此可以看出,整个server的创建和启动过程就是,主进程产生若干的子进程,子进程使用green thread启动wsgi server并等待服务。

    参考文档:

    http://www.choudan.net/2013/12/09/OpenStack-WSGI-APP%E5%AD%A6%E4%B9%A0.html

    http://developer.openstack.org/api-ref-compute-v2.html(nova的API文档)

  • 相关阅读:
    环境是如何建立的 启动文件有什么
    环境中存储的是什么
    串行 并行 异步 同步
    TPC-H is a Decision Support Benchmark
    进程通信类型 管道是Linux支持的最初Unix IPC形式之一 命名管道 匿名管道
    删除环境变量
    14.3.2.2 autocommit, Commit, and Rollback 自动提交 提交和回滚
    14.3.2.2 autocommit, Commit, and Rollback 自动提交 提交和回滚
    14.3.2.1 Transaction Isolation Levels 事务隔离级别
    14.3.2.1 Transaction Isolation Levels 事务隔离级别
  • 原文地址:https://www.cnblogs.com/littlebugfish/p/4022907.html
Copyright © 2011-2022 走看看