源码版本: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://bingotree.cn/?p=242

http://blog.csdn.net/gaoxingnengjisuan/article/details/12231633

nova-conductor与AMQP(二)的更多相关文章

  1. nova conductor

    nova conductor是一个RPC 服务,所有支持的API都在 nova.conductor.rpcapi.ConductorAPI 它是stateless,可以水平扩展. 优点: 安全: 如果 ...

  2. Nova Conductor 与 Versioned Object Model 机制

    目录 文章目录 目录 Nova Conductor 数据库访问代理机制 Versioned Object Model 机制 Nova Conductor Conductor 服务作为 Nova 核心部 ...

  3. nova-conductor与AMQP(一)

    源码版本:H版 一.AMQP基础 1. 什么是AMQP 可以参考如下文章: http://blog.csdn.net/linvo/article/details/5750987 http://blog ...

  4. OpenStack nova VM migration (live and cold) call flow

    OpenStack nova compute supports two flavors of Virtual Machine (VM) migration: Cold migration -- mig ...

  5. OpenStack 图形化服务 Horizon介绍和部署(十二)

    Horizon介绍 Horizon是一个web接口,使得云平台管理员以及用户可以管理不同的OpenStack资源以及服务. 提供一个Web界面操作OpenStack系统 使用Django框架基于Ope ...

  6. OpenStack入门篇(九)之nova服务(控制节点)的部署与测试

    1.Nova介绍 Nova是openstack最早的两块模块之一,另一个是对象存储swift.在openstack体系中一个叫做计算节点,一个叫做控制节点.这个主要和nova相关,我们把安装为计算节点 ...

  7. OpenStack之Nova模块

    Nova简介 nova和swift是openstack最早的两个组件,nova分为控制节点和计算节点,计算节点通过nova computer进行虚拟机创建,通过libvirt调用kvm创建虚拟机,no ...

  8. 为Zabbix配置Nova服务、Keystone和Placement进程CPU和内存usage监控

    目前已经完成了RabbitMQ和MySQL的监控项配置,还差对nova-api.nova-conductor.nova-scheduler和keystone进程CPU和内存 usage的监控,类似的轮 ...

  9. openstack——nova计算服务

    一.nova介绍               Nova 是 OpenStack 最核心的服务,负责维护和管理云环境的计算资源.OpenStack 作为 IaaS 的云操作系统,虚拟机生命周期管理也就是 ...

随机推荐

  1. WIN 7 发布项目

    本人工作都快两年了不知道web 怎么发布 今天我自己非常恼火!我就暗暗研究.希望能给新手指导 准备工作:WIN7 系统 .IIS 6.0.MVC (vs 新建mvc项目自带的项目) OK begin ...

  2. 【Alpha】阶段第三次Scrum Meeting

    [Alpha]阶段第三次Scrum Meeting 工作情况 团队成员 今日已完成任务 明日待完成任务 刘峻辰 更新评论接口 获取课程评论接口 赵智源 编写脚本实现持续集成 整合前端进行部署 肖萌威 ...

  3. python中 try、except、finally 的执行顺序

        def test1(): try: print('to do stuff') raise Exception('hehe') print('to return in try') return ...

  4. c# 导入第三方插件(例如pdf控件),莫名有时候成功有时候出错

    问题情境: 正如标题所述: 解决办法: 怀疑是adobe acrobat 9 pro安装文件出错:重新安装,成功. 在这过程中,尝试过福听阅读器,adobe reader等,均正常. 注:1.第三方的 ...

  5. 记录 C++ STL 中 一些好用的函数--持续更新 (for_each,transform,count_if,find_if)

    在日常的编程中,有这么几种操作还是比较常见的: 把一组数据都赋值成一个数,在一组数据中查找一个数,统计一组数据中符合条件的数等等. 一般的写法可以用循环,没有什么是循环不能搞定的.假如在这里怎么用介绍 ...

  6. hdu1242 Rescue DFS(路径探索题)

    这里我定义的路径探索题指 找某路能够到达目的地,每次走都有方向,由于是探索性的走 之后要后退 那些走过的状态都还原掉 地址:http://acm.hdu.edu.cn/showproblem.php? ...

  7. Codeforces Round #312 (Div. 2) E. A Simple Task 线段树+计数排序

    题目链接: http://codeforces.com/problemset/problem/558/E E. A Simple Task time limit per test5 secondsme ...

  8. Docker 技术 介绍

    https://github.com/docker/docker 实现用户空间隔离的技术:名称空间(NameSpace),CGroup(控制组) 什么是NameSpace::简单的理解就是,每一个虚拟 ...

  9. scrum 项目准备2.0

    1.确定选题. 应用NABCD模型,分析你们初步选定的项目,充分说明你们选题的理由. 录制为演说视频,上传到视频网站,并把链接发到团队博客上. 截止日期:2016.5.6日晚10点 演说稿: 各位领导 ...

  10. 【BioCode】根据seq与位点信息截取窗口

    代码说明 sequence24371.txt 以上为所有氨基酸的编号,序列,与位点标记.根据标记为“1”的位点,截取窗口:如下(实验结果): 图示为一个窗口为12的蛋白质片段 2N+1=25: 实现代 ...