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调用。
.
├── api.py
├── base.py
├── __init__.py
├── migration.py
└── sqlalchemyapi.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_refsqlalchemy子目录下的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))
相关文章推荐
- 另辟蹊径Ceph源码分析之2:min_size是怎么控制io是否能服务的
- android adb 源码框架分析(4 服务)
- spring cloud服务发现和注册源码分析
- Android请求注册服务过程源码分析
- Android的软件包管理服务PackageManagerService源码分析
- Tomcat源码分析(一)--服务启动
- motan源码分析四:客户端调用服务
- Android服务启动之StartService源码分析
- Hyperledger fabric 源码分析之 peer 服务启动过程
- docker1.9源码分析(五):server分配handler提供服务的流程
- Tornado源码分析之HTTP服务请求解析
- Netty 心跳服务之 IdleStateHandler 源码分析
- nsq源码分析(2):nsqlookup之tcp服务
- Dubbo源码分析之三:服务的暴露
- OpenStack Swift源码分析(3)----swift服务启动源码分析之三
- cinder服务启动源码分析
- 【OpenStack源码分析之四】WSGI与Nova API服务启动
- Android服务之PackageManagerService启动源码分析
- ResourceManager服务的AsyncDispatcher源码分析