nova-conductor与AMQP(二)
源码版本:H版
一、首先看服务的启动脚本
/usr/bin/nova-conductor
- import sys
- from nova.cmd.conductor import main
- if __name__ == "__main__":
- sys.exit(main())
nova/cmd/conductor.py
- def main():
- ...
- server = service.Service.create(binary='nova-conductor',
- topic=CONF.conductor.topic,
- manager=CONF.conductor.manager)
- service.serve(server, workers=CONF.conductor.workers)
- service.wait()
二、分析RPC服务的创建
nova/service.py
- Service类:
- @classmethod
- def create(cls, host=None, binary=None, topic=None, manager=None,
- report_interval=None, periodic_enable=None,
- periodic_fuzzy_delay=None, periodic_interval_max=None,
- db_allowed=True):
- ...
- service_obj = cls(host, binary, topic, manager,
- report_interval=report_interval,
- periodic_enable=periodic_enable,
- periodic_fuzzy_delay=periodic_fuzzy_delay,
- periodic_interval_max=periodic_interval_max,
- db_allowed=db_allowed)
- return service_obj
三、分析服务的运行
nova/service.py
- def serve(server, workers=None):
- global _launcher
- if _launcher:
- raise RuntimeError(_('serve() can only be called once'))
- """ service为nova.openstack.common.service"""
- _launcher = service.launch(server, workers=workers)
nova/openstack/common/service.py
- def launch(service, workers=None):
- if workers:
- launcher = ProcessLauncher()
- launcher.launch_service(service, workers=workers)
- else:
- launcher = ServiceLauncher()
- launcher.launch_service(service)
- return launcher
参考nova-api的服务启动过程(http://www.cnblogs.com/littlebugfish/p/4022907.html),即启动协程(使用eventlet)运行Service,主要是start函数。注意,如果在配置文件中指明多个workers的话,将有多个进程监听消息队列,取得消息的进程负责处理。接着看start函数的代码,如下:
nova/service.py
- Service类:
- def start(self):
- ...
- self.manager.pre_start_hook()
- if self.backdoor_port is not None:
- self.manager.backdoor_port = self.backdoor_port
- """创建AMQP连接,方便后面创建Consumer"""
- self.conn = rpc.create_connection(new=True)
- LOG.debug(_("Creating Consumer connection for Service %s") %
- self.topic)
- rpc_dispatcher = self.manager.create_rpc_dispatcher(self.backdoor_port)
- self.conn.create_consumer(self.topic, rpc_dispatcher, fanout=False)
- node_topic = '%s.%s' % (self.topic, self.host)
- self.conn.create_consumer(node_topic, rpc_dispatcher, fanout=False)
- self.conn.create_consumer(self.topic, rpc_dispatcher, fanout=True)
- self.conn.consume_in_thread()
- self.manager.post_start_hook()
- LOG.debug(_("Join ServiceGroup membership for this service %s")
- % self.topic)
- self.servicegroup_api.join(self.host, self.topic, self)
- if self.periodic_enable:
- if self.periodic_fuzzy_delay:
- initial_delay = random.randint(0, self.periodic_fuzzy_delay)
- else:
- initial_delay = None
- self.tg.add_dynamic_timer(self.periodic_tasks,
- initial_delay=initial_delay,
- periodic_interval_max=
- self.periodic_interval_max)
self.conn.create_consumer(node_topic, rpc_dispatcher, fanout=False)。这里的self.conn主要指nova.openstack.common.rpc.impl_qpid.Connection,(此处设AMQP后端实现为qpid,这个可以在nova.conf中进行配置)所以调用的create_consumer代码如下:
- def create_consumer(self, topic, proxy, fanout=False):
- proxy_cb = rpc_amqp.ProxyCallback(
- self.conf, proxy,
- rpc_amqp.get_connection_pool(self.conf, Connection))
- self.proxy_callbacks.append(proxy_cb)
- if fanout:
- consumer = FanoutConsumer(self.conf, self.session, topic, proxy_cb)
- else:
- consumer = TopicConsumer(self.conf, self.session, topic, proxy_cb)
- self._register_consumer(consumer)
- return consumer
该函数会根据具体的后端AMQP实现,向AMQP服务器发送队列和exchange创建(第一次会创建,后面会复用)和绑定请求,这样就可以将Consumer和具体的队列绑定并进行监听。self.conn.consume_in_thread函数就是负责启动Consumer线程,其使用evelent.spawn创建一个协程一直运行等待消息,在有消息到来时会创建新的协程运行远程调用的函数。当队列有消息到来时,调用proxy_cb进行处理,即ProxyCallback对象的__call__函数,代码如下:
nova/openstack/common/rpc/amqp.py
- ProxyCallback类:
- def __call__(self, message_data):
- if hasattr(local.store, 'context'):
- del local.store.context
- rpc_common._safe_log(LOG.debug, _('received %s'), message_data)
- self.msg_id_cache.check_duplicate_message(message_data)
- ctxt = unpack_context(self.conf, message_data)
- """解析消息"""
- method = message_data.get('method')
- args = message_data.get('args', {})
- version = message_data.get('version')
- namespace = message_data.get('namespace')
- if not method:
- LOG.warn(_('no method for message: %s') % message_data)
- ctxt.reply(_('No method for message: %s') % message_data,
- connection_pool=self.connection_pool)
- return
- """处理消息"""
- self.pool.spawn_n(self._process_data, ctxt, version, method,
- namespace, args)
- def _process_data(self, ctxt, version, method, namespace, args):
- ctxt.update_store()
- try:
- rval = self.proxy.dispatch(ctxt, version, method, namespace,
- **args)
- ...
可以看到消息的处理主要是通过新开的协程(使用eventlet)来执行self._process_data函数,而self._process_data函数中主要调用了self.proxy.dispatch函数,那么这个dispatch函数的内容究竟是什么呢?
1、首先找到self.proxy
根据对self.proxy的层层追踪,其为上面ProxyCallback构造时传入,即start函数中的 rpc_dispatcher = self.manager.create_rpc_dispatcher(self.backdoor_port),这里的self.manager在创建该Service的时候就已经设定为ConductorManager。ConductorManager的create_rpc_dispatcher函数代码如下:
- def create_rpc_dispatcher(self, *args, **kwargs):
- #self.compute_task_mgr = ComputeTaskManager()
- kwargs['additional_apis'] = [self.compute_task_mgr]
- return super(ConductorManager, self).create_rpc_dispatcher(*args,
- **kwargs)
根据类的继承关系:
nova/manager.py
- Manager类:
- def create_rpc_dispatcher(self, backdoor_port=None, additional_apis=None):
- apis = []
- if additional_apis:
- apis.extend(additional_apis)
- base_rpc = baserpc.BaseRPCAPI(self.service_name, backdoor_port)
- apis.extend([self, base_rpc])
- serializer = objects_base.NovaObjectSerializer()
- return rpc_dispatcher.RpcDispatcher(apis, serializer)
nova/openstack/common/rpc/dispatcher.py
- RpcDispatcher类
- def __init__(self, callbacks, serializer=None):
- #callbacks为一个list,包含ComputeTaskManager,ConductorManager,BaseRPCAPI
- self.callbacks = callbacks
- if serializer is None:
- serializer = rpc_serializer.NoOpSerializer()
- self.serializer = serializer
- super(RpcDispatcher, self).__init__()
所以最后的self.proxy为RpcDispatcher对象。要注意的是RpcDispatcher对象的callbacks属性包含了一系列的Manager类,它们将被用来处理消息中指定的method。参考下图:
2、分析self.proxy.dispatch函数
即RpcDispatcher类的dispatch函数,代码如下:
- def dispatch(self, ctxt, version, method, namespace, **kwargs):
- if not version:
- version = '1.0'
- had_compatible = False
- for proxyobj in self.callbacks:
- try:
- cb_namespace = proxyobj.RPC_API_NAMESPACE
- except AttributeError:
- cb_namespace = None
- if namespace != cb_namespace:
- continue
- ...
- if not hasattr(proxyobj, method):
- continue
- if is_compatible:
- kwargs = self._deserialize_args(ctxt, kwargs)
- result = getattr(proxyobj, method)(ctxt, **kwargs)
- return self.serializer.serialize_entity(ctxt, result)
- ...
该函数会根据namespace匹配Manager,然后分析Manager类中的函数是否和消息中的函数匹配,如果匹配即调用Manager类中对应的函数进行处理。经过观察,其实对外提供rpc服务的组件的rpcapi.py和manager.py文件中的类是对应的,它们通过namespace进行匹配查找,在命名上具有相同的前缀,所以如果要跟踪rpcapi.py中函数的后续实现只需查看该组件的manager.py文件里对应的Manager类的对应函数就可以了。
参考文章:
http://blog.csdn.net/gaoxingnengjisuan/article/details/12231633
nova-conductor与AMQP(二)的更多相关文章
- nova conductor
nova conductor是一个RPC 服务,所有支持的API都在 nova.conductor.rpcapi.ConductorAPI 它是stateless,可以水平扩展. 优点: 安全: 如果 ...
- Nova Conductor 与 Versioned Object Model 机制
目录 文章目录 目录 Nova Conductor 数据库访问代理机制 Versioned Object Model 机制 Nova Conductor Conductor 服务作为 Nova 核心部 ...
- nova-conductor与AMQP(一)
源码版本:H版 一.AMQP基础 1. 什么是AMQP 可以参考如下文章: http://blog.csdn.net/linvo/article/details/5750987 http://blog ...
- OpenStack nova VM migration (live and cold) call flow
OpenStack nova compute supports two flavors of Virtual Machine (VM) migration: Cold migration -- mig ...
- OpenStack 图形化服务 Horizon介绍和部署(十二)
Horizon介绍 Horizon是一个web接口,使得云平台管理员以及用户可以管理不同的OpenStack资源以及服务. 提供一个Web界面操作OpenStack系统 使用Django框架基于Ope ...
- OpenStack入门篇(九)之nova服务(控制节点)的部署与测试
1.Nova介绍 Nova是openstack最早的两块模块之一,另一个是对象存储swift.在openstack体系中一个叫做计算节点,一个叫做控制节点.这个主要和nova相关,我们把安装为计算节点 ...
- OpenStack之Nova模块
Nova简介 nova和swift是openstack最早的两个组件,nova分为控制节点和计算节点,计算节点通过nova computer进行虚拟机创建,通过libvirt调用kvm创建虚拟机,no ...
- 为Zabbix配置Nova服务、Keystone和Placement进程CPU和内存usage监控
目前已经完成了RabbitMQ和MySQL的监控项配置,还差对nova-api.nova-conductor.nova-scheduler和keystone进程CPU和内存 usage的监控,类似的轮 ...
- openstack——nova计算服务
一.nova介绍 Nova 是 OpenStack 最核心的服务,负责维护和管理云环境的计算资源.OpenStack 作为 IaaS 的云操作系统,虚拟机生命周期管理也就是 ...
随机推荐
- 第四次ScrumMeeting博客
第四次ScrumMeeting博客 本次会议于10月28日(六)22时整在3公寓725房间召开,持续15分钟. 与会人员:刘畅.辛德泰.窦鑫泽.张安澜.赵奕. 1. 每个人的工作(有Issue的内容和 ...
- 动态语言的灵活性是把双刃剑 -- 以 Python 语言为例
本文有些零碎,总题来说,包括两个问题:(1)可变对象(最常见的是list dict)被意外修改的问题,(2)对参数(parameter)的检查问题.这两个问题,本质都是因为动态语言(动态类型语言)的特 ...
- 大数据-storm学习资料视频
storm学习资料视频 https://pan.baidu.com/s/18iQPoVFNHF1NCRBhXsMcWQ
- wepy中如何使用stylus等样式预处理器
wepy中如何使用stylus等样式预处理器 一.如何在wepy中使用stylus 1.安装wepy-compiler-stylus(以及stylus, stylus-loader) npm inst ...
- Win10系统自带输入法的人机交互设计
过了寒假回校以后,我的电脑重装了系统,为了提升系统运行的速度,自己装了一个内存条同时对硬盘进行了重新的分区,对电脑内的文件也进行了重新的整理,电脑的运行速度提高了很多.老多同学都说win10系统好用, ...
- OOP 1.5 类和对象的基本概念与用法1
1.定义 面向对象的基本特点:抽象.封装.继承.多态 面向对象程序设计方法:将某类客观事物的共同特点归纳出来,形成一个数据结构 抽象:将事物所能进行的行为归纳出来,形成一个个函数,这些函数可以用来操作 ...
- 做更好的自己 ——读《我是IT小小鸟》有感
转眼间大一已经过了一大半了,到了大学,才发现初高中时父母所说的“到了大学你就轻松了···”都是骗人的.但我脑海里却一直被这个观点所支配,以至于我在大一上学期里无所事事,不知道干些什么.学习也没重视,分 ...
- 0324操作系统cmd功能的扩展
需求:1.实现清屏功能 2.实现不区分大小写功能 3.添加功能能添加新的命令符 设计:1.使用system("cls")清屏. 2.使用strlwr()函数把大写都变成小写 3.( ...
- psp 第二周
11号 12号 类别c 内容c 开始时间s 结 ...
- Jmeter 快速入门--初识线程组
添加线程组 (1)thread group(线程组),setup thread group相当于lr初始化“环境”的初始化脚本,teardown thread group相当于lr测试完毕后对应的清除 ...