跟 Keystone 相比,Nova 的服务类型就要多一点了,如 nova-api、nova-compute、nova-scheduler、nova-conductor 等(可通过 ps -ef | grep nova 查看得到),具体可查阅官方文档 Compute service overview。其中,nova-api 跟另外的服务不一样的地方在于它是一个 WSGI 服务,用于接收 REST API 请求,再将请求转发给其他服务(如 nova-compute)。也就是说,nova-api 是一个应用层的服务,其余的是逻辑层的服务。
在源码中,nova-api 服务的启动方式跟其余服务的启动方式不一样,所以下文将会分成两个部分来说明,即 nova-api 的服务启动以及以 nova-compute 为代表的服务启动。
nova-api 服务
对于 WSGI 服务,我们一般需要从 setup.cfg 和 api-paste.ini 这两个文件入手就可以了。我们先来看一下 setup.cfg 文件内容:
1 | ...... |
也就是说,nova-api 服务的入口在 nova/cmd/api.py 的 main 函数:
1 | # nova/cmd/api.py |
其中,gmr.TextGuruMeditation.setup_autorun(version)
表示开启 Guru Meditation Report(通用的错误报告产生框架),以便于排错。这里我们暂不详说。
另外一个值得注意的是 enabled_apis
,在 /etc/nova/nova.conf 可以看到其值为 osapi_compute,metadata
,也就是说 nova api 实际真正启动了 osapi_compute(“真正” nova-api)及 metadata 两个服务。我们接着往下看:
1 | # nova/service.py |
也就是说,osapi_compute 及 metadata 的服务需要由 PasteDeploy 来加载,它们的配置如下:
1 | # etc/nova/api-paste.ini |
到此,nova-api 的服务启动核心部分就说完了。关于其他相关的 Guru Meditation Report、Metadata、Eventlet 等,因为以后会说到,这里就暂不表。
服务启动之后效果如下:
nova-compute 服务
因为除了 nova-api 服务的启动方式稍微有点不一样,其他的服务的都是类似的,这里我们就以 nova-compute 为例来说明,其他的服务只要以此类推就可以了。另外,值得说明的是,nova-compute 服务的启动相对其他其实要复杂得多。
同样,对于 nova-compute 服务,我们也从 setup.cfg 入手:
1 | ...... |
看下服务启动代码:
1 | # nova/cmd/compute.py |
不仔细研究代码就不知道这 10 几行代码所涵盖的复杂度。这里特意花了一个 nova-compute 服务启动的概览(图有点大,页面看不清楚,可右键下载查看):
能够仔细看完这张图的一定是真爱…下边我们挑一些重点的来说。
数据库访问
在以上 main 函数中,代码明确说明了不能直接访问数据库,否则报错:
1 | # nova/cmd/compute.py |
而只能通过 conductor 来远程访问(RPC)数据库:
1 | # nova/cmd/compute.py |
也就是说,每当 nova-compute 服务有访问数据库的请求时,它都会调用 nova-conductor 的 rpcapi,从而实现对数据库的读写。这里的 RPC 调用实际是 nova-compute 向消息队列(RabbitMQ)发送 topic 为 CONF.conductor.topic 的消息,而 nova-conductor 又监听该 topic,所以就实现了对 nova-conductor 的调用。这个远程调用过程可参考博文深入研究 Openstack Nova 组件对象模型以及数据库访问机制。
注:Nova 模块以前支持 nova-compute 直接操作数据库而不经过 nova-conductor,具体由配置文件中的 use_local 字段来决定。但在这个最新的版本(Ocata),这个字段就直接废除了:
1 | # releasenotes/notes/rm-conductor-local-apis-f121afaee99f6fa4.yaml |
服务初始化及启动
千言不如一图(下图单独拆分成了服务初始化、启动两部分):
RPC 服务
RPC 服务非常重要,因为在 Nova 中,几个重要的服务 nova-compute、nova-conductor、nova-scheduler 互相之间只能通过 RPC 来实现调用,所以这几个服务都会在启动的时候开启 RPC 服务,监听消息队列中的信息。
在 RPC 启动 RPCServer 之前,对 Transport、Notifier 进行了初始化,详细可参考下图:
接下来就是服务启动了(注意 topic):
RPC 服务启动完成后,其他模块想向 nova-compute 发送请求的时候,直接调用 nova-comptue 的 rpcapi 就可以了。
定时任务
定时任务也是非常重要的一块。有两类定时任务,时间间隔固定
和时间间隔动态决定
两种,前一种的有服务状态定时上报(servicegroup.drivers.db::DbDriver::_report_state),后一种的主要跟虚拟机相关,如检查虚拟机 build 时间(compute.manager::ComputeManager::_check_instance_build_time)。详细请参考下图:
花这些图花了差不多两个星期(每天 1.5 个小时左右)…