您的位置:首页 > 其它

Nova Conductor服务源码分析

2018-03-23 20:21 253 查看
Conductor服务nova-conductor最初于Grizzly版本发布,目的是为数据库访问提供一层安全机制。在此之前,nova-compute都是直接访问数据库,一旦被攻破,则数据库会面临直接暴露的危险。此外,nova-conductor的加入也使得nova-compute与数据库解耦,因此在保证conductor API兼容性的前提下,数据库schema升级的同时并不需要去升级nova-compute。nova-conductor对数据库访问的性能也有相应的提高,此前当使用协程时,所有数据库访问都是阻塞的,引入nova-conductor之后,就可以通过创建多个协程使用RPC访问nova-conductor改善这个问题。当然这么做不可避免有一些限制,RPC调用是有延迟的,nova-conductor本身访问数据库也是有阻塞的,当部署nova-conductor实例较少时,阻塞现象会更加突出性能的问题。目前为止,nova-compute所有访问数据库的动作都要交给nova-conductor完成,出于完全性考虑,应该避免nova-conductor和nova-compute部署在同一服务器上,否则移除数据库直接访问就没有任何意义了,随着nova-conductor服务的不断完善,它还需要承当部分原本由nova-compute负责的TaskAPI任务,TaskAPI主要包含耗时较长的任务,比如创建虚拟机,迁移虚拟机等。Conductor服务的源码位于nova/conductor目录:├── api.py
├── __init__.py
├── manager.py
├── rpcapi.py
└── tasks
    ├── live_migrate.py
一般来说rpcapi.py文件与RPC相关,其他服务将这个模块导入就可以使用它提供的接口远程调用nova-conductor提供的服务,nova-conductor注册的RPC Server接受到RPC请求后,再由manager.py文件中的类ConductorManager真正地完成数据库访问的操作。但是基于数据库访问的特殊性,api.py文件中又对RPC的调用做了一层封装,其他模块需要导入的是api模块,而不是rpcapi模块。而数据库访问的特殊性在于需要区分是不是需要通过RPC,api.py里定义了四个类:LocalAPI,API,LocalComputerTaskAPI以及ComputerTaskAPI。前两个类是nova-conductor访问数据库的接口,后两个是TaskAPI接口。nova-conductor和nova-compute部署在一个节点时,并不需要通过RPC调用去访问数据库,此时通过类LocalAPI直接操作数据库,否则,会通过类API使用recapi.py中定义的类ConductorAPI发送RPC请求给nova-conductor远程访问数据库。同样对于TaskAPI任务,nova-api和nova-conductor部署在一起时,会使用类LocalComputerTaskAPI,也不需要经过RPC调用。
# nova/conductor/__init__.py
from nova.conductor import api as conductor_api
def API(*args, **kwargs):
#根据配置选项use_local的定义判断nova-conductor是否与nova-compute部署在
#同一个节点上,如果是则使用LocalAPI访问数据库,否则通过API使用RPC访问
use_local = kwargs.pop('use_local', False)
if oslo.config.cfg.CONF.conductor.use_local or use_local:
api = conductor_api.LocalAPI
else:
api = conductor_api.API
return api(*args, **kwargs)
def ComputeTaskAPI(*args, **kwargs):
use_local = kwargs.pop('use_local', False)
if oslo.config.cfg.CONF.conductor.use_local or use_local:
api = conductor_api.LocalComputeTaskAPI
else:
api = conductor_api.ComputeTaskAPI
return api(*args, **kwargs)
对于数据访问,无论是本地访问或者通过远程调用,最终真正完成数据操作的都是manager.py里的类ConductorManager。对于nova-conductor提供的TaskAPI功能,目前只有Nova API服务会用到,同样无论是否通过RPC远程调用,最终完成任务都是manager.py里的类ComputerTaskManager,而部分TaskAPI任务,会由ComputerTaskManager调用nova/conductor/tasks目录的模块完成。
#nova/conductor/manager.py
class ConductorManager(manager.Manager):
@messaging.expected_exceptions(exception.InstanceNotFound)
def instance_get_by_uuid(self, context, instance_uuid,
columns_to_join):
return jsonutils.to_primitive(
self.db.instance_get_by_uuid(context, instance_uuid,
columns_to_join))
ConductorManager继承自nova. manager.Manager,而nova. manager.Manager又继承自nova.db.base.Base,类Base会根据配置选项db_drive的定义导入相应数据库操作模块,默认为nova.db模块。nova.db模块目录结构如下:[root@localhost db]# tree -L 1
.
├── api.py
├── base.py
├── __init__.py
├── migration.py
└── sqlalchemyapi.py提供了数据库对外接口。
#nova/nova/db/api.py
def service_create(context, values):
"""Create a service from the values dictionary."""
return IMPL.service_create(context, values)
而sqlalchemy/api.py文件提供了对这些接口真正的实现。
#nova/db/sqlalchemy/api.py
@require_admin_context
def service_create(context, values):
service_ref = models.Service()
service_ref.update(values)
if not CONF.enable_new_services:
service_ref.disabled = True
try:
service_ref.save()
except db_exc.DBDuplicateEntry as e:
if 'binary' in e.columns:
raise exception.ServiceBinaryExists(host=values.get('host'),
binary=values.get('binary'))
raise exception.ServiceTopicExists(host=values.get('host'),
topic=values.get('topic'))
return service_ref
sqlalchemy子目录下的models.py文件定义了每一个类都对应数据库的一张表。#nova/db/sqlalchemy/models.py
class Certificate(BASE, NovaBase):
"""Represents a x509 certificate."""
__tablename__ = 'certificates'
__table_args__ = (
Index('certificates_project_id_deleted_idx', 'project_id', 'deleted'),
Index('certificates_user_id_deleted_idx', 'user_id', 'deleted')
)
id = Column(Integer, primary_key=True)
user_id = Column(String(255))
project_id = Column(String(255))
file_name = Column(String(255))
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  nova