前段时间撰文分析了“云主机的启动过程”源码,读者应该注意到了nova-scheduler
,nova-compute
等组件是通过发起rpc.cast
, rpc.call
调用完成交互的。那今天我打算介绍下nova-compute
服务的启动过程,并重点分析下其与AMQP(rabbitmq)链接的建立过程。
在CentOS 7中启动nova-compute
服务,执行路径是这样的:
systemctl start openstack-nova-compute.service
-> /usr/bin/nova-compute
-> nova/cmd/compute.py/main
下面从入口main
开始分析,函数如下:
def main():
"""加载和设置配置参数,有两点需要注意:
1. 调用rpc.set_defaults设置默认的exchange为nova,如果不设置则为
openstack
2. 调用rpc.init设置Transport和Notifier,Transport是
oslo_messaging/transport.py/Transport实例,我采用的是默认的
rpc_backend=rabbit,所以Transport采用的driver=oslo_messaging/
_drivers/impl_rabbit.py/RabbitDriver;Notifier是一个通知消息发
送器,它借助Transport完成通知消息的发送
"""
config.parse_args(sys.argv)
#省略其他配置代码
.......
"""调用类方法nova/service.py/Service.create创建Service服务对象
输入参数topic = compute, db_allowd = false;`create`方法是一个
类方法(@classmethod),它首先基于输入参数和(/etc/nova.conf中的选
项)设置配置,然后创建一个Service对象并返回给调用者
"""
server = service.Service.create(binary='nova-compute',
topic=CONF.compute_topic,
db_allowed=CONF.conductor.use_local)
"""调用server方法启动服务并调用wait方法等待服务启动完成,serve方法创
建Launcher服务启动实例对象(这里是ServiceLauncher)来启动服务,
但最终会调用server.start方法启动服务。
"""
service.serve(server)
service.wait()
后文的分析将分两步进行:
Service
对象的初始化Service
的启动
Service
对象的初始化
上文说到create
方法会创建一个Service
对象,下面一起来看看其构造函数:
def __init__(self, host, binary, topic, manager,
report_interval=None,
periodic_enable=None, periodic_fuzzy_delay=None,
periodic_interval_max=None, db_allowed=True,
*args, **kwargs):
"""nova/service.py/Service.__init__
输入参数如下:
host = 'devstack'
binary = 'nova-compute'
topic = 'compute'
manager = 'nova.compute.manager.ComputeManager'
report_interval = 10
periodic_enable = True
periodic_fuzzy_delay = 60
periodic_interval_max = None
db_allowed = False
args = ()
kwargs = {}
构造函数中主要实现了如下功能:
1. 成员变量赋值
2. 初始化ComputeManager对象
3. 初始化conductor API对象
后文重点分析2和3
"""
super(Service, self).__init__()
self.host = host
self.binary = binary
self.topic = topic
self.manager_class_name = manager
#实例化servicegroup API(nova/servicegroup/api.py/API)
#CONF.servicegroup_driver指定所使用的存储驱动(可以是db,
#zookeeper,memcache,默认是db)
self.servicegroup_api = servicegroup.API()
#实例化ComputeManager(nova/compute/manager.py/ComputeManager)
manager_class =
importutils.import_class(self.manager_class_name)
self.manager = manager_class(host=self.host, *args, **kwargs)
self.rpcserver = None
self.report_interval = report_interval
self.periodic_enable = periodic_enable
self.periodic_fuzzy_delay = periodic_fuzzy_delay
self.periodic_interval_max = periodic_interval_max
self.saved_args, self.saved_kwargs = args, kwargs
self.backdoor_port = None
#实例化conductor API(nova/conductor/api.py/API)
self.conductor_api = conductor.API(use_local=db_allowed)
#发送ping消息,等待nova-conductor服务准备就绪
self.conductor_api.wait_until_ready(
context.get_admin_context())
实例化ComputeManager
ComputeManager实例化,就是创建ComputeManager对象,然后调用其__init__
方法,创建各种api接口及client rpc api,如:network、volume、image、conductor等,代码如下:
def __init__(self, compute_driver=None, *args, **kwargs):
"""Load configuration options and connect to the
hypervisor.
"""
"""nova/compute/manager.py/ComputeManager.__init__
api的创建都是根据配置(/etc/nova.conf)中指定的类名称,然后创建
对应的API类实例,具体的类请看注释; 而client rpc api则是
#创建一个RPCClient实例并与特定的Target(指定了消息的发送目的
地)及Transport(消息传输层)关联,后文以
`nova/compute/rpcapi.py/ComputeAPI`为例分析具体的实现
"""
#nova/compute/manager.py/ComputeVirtAPI
self.virtapi = ComputeVirtAPI(self)
#nova/network/neutronv2/api.py/API
self.network_api = network.API()
#nova/volume/cinder.py/API
self.volume_api = volume.API()
#nova/image/api.py/API
self.image_api = image.API()
self._last_host_check = 0
self._last_bw_usage_poll = 0
self._bw_usage_supported = True
self._last_bw_usage_cell_update = 0
#nova/compute/api.py/API
self.compute_api = compute.API()
#nova/compute/rpcapi.py/ComputeAPI
#消息Target = {topic='compute', version='4.0'}
self.compute_rpcapi = compute_rpcapi.ComputeAPI()
"""nova/conductor/api.py/API,内部实现如下:
创建`nova/conductor/rpcapi.py/ConductorAPI`实例,
内部会创建一个rpc client,其Target如下:
Target = {topic = 'conductor', version = '3.0'}
创建`nova/baserpc.py/BaseAPI`实例,内部会创建一个rpc
client其Target如下:
Target = {topic = 'conductor',
namespace = 'baseapi', version = '1.0'}
"""
self.conductor_api = conductor.API()
"""nova/conductor/rpc.py/ComputeTaskAPI
1. nova/conductro/rpcapi.py/ComputeTaskAPI
Target = {topic = 'conductor',
namespace = 'compute_task', version = '1.0'}
"""
self.compute_task_api = conductor.ComputeTaskAPI()
#如果security_group_api配置为neutron或者quantum,则为True
self.is_neutron_security_groups = (
openstack_driver.is_neutron_security_groups())
#nova/consoleauth/rpcapi.py/ConsoleAuthAPI
# Target = {topic = 'consoleauth', version = '2.1'}
self.consoleauth_rpcapi = consoleauth.rpcapi.ConsoleAuthAPI()