源码版本: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

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

接着,分析如下:

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

  1. def main():
  2. config.parse_args(sys.argv)
  3. logging.setup("nova")
  4. utils.monkey_patch()
  5.  
  6. launcher = service.process_launcher()
  7. for api in CONF.enabled_apis:
  8. should_use_ssl = api in CONF.enabled_ssl_apis
  9. if api == 'ec2':
  10. """为了与ec2兼容"""
  11. server = service.WSGIService(api, use_ssl=should_use_ssl,
  12. max_url_len=16384)
  13. else:
  14. server = service.WSGIService(api, use_ssl=should_use_ssl) 1
  15. launcher.launch_service(server, workers=server.workers or 1)【2
  16. """当前进程处于等待状态"""
  17.   launcher.wait()

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

/nova/service.py

  1. WSGIService类:
  2. def __init__(self, name, loader=None, use_ssl=False, max_url_len=None):
  3. self.name = name
  4. self.manager = self._get_manager()
  5. self.loader = loader or wsgi.Loader()
  6. self.app = self.loader.load_app(name)
  7. self.host = getattr(CONF, '%s_listen' % name, "0.0.0.0")
  8. self.port = getattr(CONF, '%s_listen_port' % name, 0)
  9. self.workers = getattr(CONF, '%s_workers' % name, None)
  10. self.use_ssl = use_ssl
  11. """封装了wsgi.py中的server"""
  12. self.server = wsgi.Server(name,
  13. self.app,
  14. host=self.host,
  15. port=self.port,
  16. use_ssl=self.use_ssl,
  17. max_url_len=max_url_len)
  18. # Pull back actual port used
  19. self.port = self.server.port
  20. self.backdoor_port = None

/nova/wsgi.py

  1. Loader类:
  2. def __init__(self, config_path=None):
  3.   """试图寻找api-paste.ini配置文件"""
  4.   self.config_path = None
  5.  
  6.   config_path = config_path or CONF.api_paste_config
  7.   if not os.path.isabs(config_path):
  8.     self.config_path = CONF.find_file(config_path)
  9.   elif os.path.exists(config_path):
  10.     self.config_path = config_path
  11.  
  12.   if not self.config_path:
  13.     raise exception.ConfigNotFound(path=config_path)
  14.  
  15. def load_app(self, name):
  16.   try:
  17.     LOG.debug("Loading app %(name)s from %(path)s",
  18. {'name': name, 'path': self.config_path})
  19.     return deploy.loadapp("config:%s" % self.config_path, name=name)
  20.   except LookupError as err:
  21.     LOG.error(err)
  22.     raise exception.PasteAppNotFound(name=name, path=self.config_path)

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

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

/nova/openstack/common/service.py

  1. ProcessLauncher类:
  2. def launch_service(self, service, workers=1):
  3.   wrap = ServiceWrapper(service, workers)
  4.  
  5.   LOG.info(_('Starting %d workers'), wrap.workers)
  6.   """循环启动workers数目的子进程"""
  7.   while self.running and len(wrap.children) < wrap.workers:
  8.     self._start_child(wrap)
  9.  
  10. def _start_child(self, wrap):
  11.   ...
  12.   """创建子进程"""
  13.   pid = os.fork()
  14.   if pid == 0:
  15.  
  16.     status = 0
  17.     try:
  18.       """子进程进行处理"""
  19.       self._child_process(wrap.service)
  20.     except SignalExit as exc:
  21.       signame = {signal.SIGTERM: 'SIGTERM',
  22. signal.SIGINT: 'SIGINT'}[exc.signo]
  23.       LOG.info(_('Caught %s, exiting'), signame)
  24.       status = exc.code
  25.     except SystemExit as exc:
  26.       status = exc.code
  27.     except BaseException:
  28.       LOG.exception(_('Unhandled exception'))
  29.       status = 2
  30.     finally:
  31.       """出现异常停掉服务"""
  32.       wrap.service.stop()
  33.     """子进程退出"""
  34.     os._exit(status)
  35.  
  36.   LOG.info(_('Started child %d'), pid)
  37.   wrap.children.add(pid)
  38.   self.children[pid] = wrap
  39.   return pid
  40.  
  41. def _child_process(self, service):
  42.   ...
  43.   launcher = Launcher()
  44.   launcher.run_service(service)

/nova/openstack/common/service.py

  1. Launcher类:
  2. def __init__(self):
  3. self._services = threadgroup.ThreadGroup()
  4. self.backdoor_port = eventlet_backdoor.initialize_if_enabled()
  5.  
  6. @staticmethod
  7. def run_service(service):
  8. service.start()
  9. service.wait()

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

/nova/service.py

  1. WSGIService类:
  2. def start(self):
    if self.manager:
  3. self.manager.init_host()
  4. self.manager.pre_start_hook()
  5. if self.backdoor_port is not None:
  6. self.manager.backdoor_port = self.backdoor_port
  7. self.server.start()
  8. if self.manager:
  9. self.manager.post_start_hook()
  10.  
  11. def wait(self):
  12. self.server.wait()

/nova/wsgi.py

  1. Server类:
  2. def start(self):
  3. ...
  4. wsgi_kwargs = {
  5. 'func': eventlet.wsgi.server,
  6. 'sock': self._socket,
  7. 'site': self.app,
  8. 'protocol': self._protocol,
  9. 'custom_pool': self._pool,
  10. 'log': self._wsgi_logger,
  11. 'log_format': CONF.wsgi_log_format
  12. }
  13.  
  14. if self._max_url_len:
  15. wsgi_kwargs['url_length_limit'] = self._max_url_len
  16. """创建一个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"""
  17. self._server = eventlet.spawn(**wsgi_kwargs)
  18.  
  19. def wait(self):
  20. try:
  21. """green thread阻塞等待"""
  22. self._server.wait()
  23. except greenlet.GreenletExit:
  24. 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文档)

nova-api源码分析(WSGI server的创建及启动)的更多相关文章

  1. spark 源码分析之四 -- TaskScheduler的创建和启动过程

    在 spark 源码分析之二 -- SparkContext 的初始化过程 中,第 14 步 和 16 步分别描述了 TaskScheduler的 初始化 和 启动过程. 话分两头,先说 TaskSc ...

  2. kube-scheduler源码分析(1)-初始化与启动分析

    kube-scheduler源码分析(1)-初始化与启动分析 kube-scheduler简介 kube-scheduler组件是kubernetes中的核心组件之一,主要负责pod资源对象的调度工作 ...

  3. dubbo源码分析3-service bean的创建与发布

    dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...

  4. vscode源码分析【七】主进程启动消息通信服务

    第一篇: vscode源码分析[一]从源码运行vscode 第二篇:vscode源码分析[二]程序的启动逻辑,第一个窗口是如何创建的 第三篇:vscode源码分析[三]程序的启动逻辑,性能问题的追踪 ...

  5. vscode源码分析【三】程序的启动逻辑,性能问题的追踪

    第一篇: vscode源码分析[一]从源码运行vscode 第二篇:vscode源码分析[二]程序的启动逻辑,第一个窗口是如何创建的 启动追踪 代码文件:src\main.js 如果指定了特定的启动参 ...

  6. Spring源码分析之Bean的创建过程详解

    前文传送门: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 Spring源码分析之BeanFactoryPostProcessor调用过程详解 本文内容: 在 ...

  7. Apache Kafka源码分析 – Broker Server

    1. Kafka.scala 在Kafka的main入口中startup KafkaServerStartable, 而KafkaServerStartable这是对KafkaServer的封装 1: ...

  8. Kafka源码分析(三) - Server端 - 消息存储

    系列文章目录 https://zhuanlan.zhihu.com/p/367683572 目录 系列文章目录 一. 业务模型 1.1 概念梳理 1.2 文件分析 1.2.1 数据目录 1.2.2 . ...

  9. MyCat源码分析系列之——配置信息和启动流程

    更多MyCat源码分析,请戳MyCat源码分析系列 MyCat配置信息 除了一些默认的配置参数,大多数的MyCat配置信息是通过读取若干.xml/.properties文件获取的,主要包括: 1)se ...

随机推荐

  1. Python3基础-表达式和运算符

    表达式和运算符 什么是表达式? 1+2*3就是一个表达式,这里的加号和乘号叫做运算符,1.2.3叫做操作数. 1+2*3经过计算后得到的结果是7,我们可以将计算结果存放在一个变量里,result=1+ ...

  2. Asphalting Roads(翻译!)

    Description City X consists of n vertical and n horizontal infinite roads, forming n × n intersectio ...

  3. 404 Note Found· 第七次作业 - 需求分析报告

    目录 组队后的团队项目的整体计划安排 项目logo及思维导图 项目logo 思维导图 产品思维导图 产品思维导图-引导 产品思维导图-后端数据处理.存储 产品思维导图-短信识别 产品思维导图-智能分析 ...

  4. 团队项目选题报告(I know)

    一.团队成员及分工 团队名称:I know 团队成员: 陈家权:选题报告word撰写 赖晓连:ppt制作,原型设计 雷晶:ppt制作,原型设计 林巧娜:原型设计,博客随笔撰写 庄加鑫:选题报告word ...

  5. lintcode-445-余弦相似度

    445-余弦相似度 Cosine similarity is a measure of similarity between two vectors of an inner product space ...

  6. C++ Primer Plus学习:第八章

    C++入门第八章:函数探幽 本章将介绍C++语言区别于C语言的新特性.包括内联函数.按引用传递变量.默认的参数值.函数重载以及函数模板. 1 C++内联函数 内联函数是C++为提高程序运行速度所做的一 ...

  7. (二)java.util.Scanner的使用

    Scanner是一个使用正则表达式来解析基本类型和字符串的简单文本扫描器.Scanner 使用分隔符模式将其输入分解为标记,默认情况下该分隔符模式与空白匹配.然后可以使用不同的 next 方法将得到的 ...

  8. TCP系列42—拥塞控制—5、Linux中的慢启动和拥塞避免(二)

    在本篇中我们继续上一篇文章wireshark的示例讲解,上一篇介绍了一个综合示例后,本篇介绍一些简单的示例,在读本篇前建议先把上一篇读完,为了节省篇幅,本篇只针对一些特殊的场景点报文进行讲解,不会像上 ...

  9. 第二周:PSP&进度条

    PSP: 一.词频统计改进 1.表格:     C类型 C内容 S开始时间 E结束时间 I时间间隔 T净时间(mins) 预计花费时间(hrs) 学习 <构建之法>.Java 8:46 1 ...

  10. 某客的《微信小程序》从基础到实战视频教程

    第 1 部分 微信小程序从基础到实战课程概要   第 1 节 微信小程序从基础到实战课程概要   1.1微信小程序从基础到实战课程概要   第 2 部分 初识微信小程序    第 1 节 微信小程序简 ...