nova-conductor与AMQP(一)
源码版本:H版
一、AMQP基础
1、 什么是AMQP
可以参考如下文章:
http://blog.csdn.net/linvo/article/details/5750987
http://blog.csdn.net/gaoxingnengjisuan/article/details/11468061
2、 nova中的AMQP
可以参考如下文章:
http://docs.openstack.org/developer/nova/devref/rpc.html
3、 Qpid操作(RabbitMQ也有相应的命令查看消息队列情况)
1)安装qpid工具:
https://qpid.apache.org/download.html(安装C++ broker command-line tools 和 QMF)
2)使用qpid-tool命令查看消息队列详情,具体操作可以用help参数查看
二、以nova-conductor为例具体分析
凡是对外提供RPC调用的组件都会包含rpcapi.py文件,将这些调用放在该文件中。如果需要对这些组件进行rpc调用,只需导入这个rpcapi.py文件,然后创建相应的类,调用相应的函数。
在rpcapi.py中一般API类的函数都是调用self.client的cast函数或call函数发送消息。其中,cast函数是异步的,不需要返回结果,而call函数是同步的,需要等待结果返回。我们需要进一步了解这个self.client对象。在这些API类的构造函数中我们发现self.client对象都是通过self.get_client函数获得,由于这些API类都继承nova.rpcclient.RpcProxy类,所以其调用的get_client函数就是nova.rpcclient.RpcProxy中的get_client,该方法获得的实例为nova.rpcclient.RPCClient对象。总的来说,就是rpcapi.py中的类方法都是借用nova.rpcclient.RPCClient对象的cast或call进行消息的发送。
以nova.conductor.rpcapi.ComputeTaskAPI的 build_instances函数为例,这里希望通过该api调用nova-conductor为我们建立虚拟机,进一步的分析如下:
def build_instances(self, context, instances, image, filter_properties,
admin_password, injected_files, requested_networks,
security_groups, block_device_mapping, legacy_bdm=True):
instances_p = [jsonutils.to_primitive(inst) for inst in instances]
image_p = jsonutils.to_primitive(image)
cctxt = self.client.prepare(version='1.5')
cctxt.cast(context, 'build_instances',
instances=instances_p, image=image_p,
filter_properties=filter_properties,
admin_password=admin_password,
injected_files=injected_files,
requested_networks=requested_networks,
security_groups=security_groups,
block_device_mapping=block_device_mapping,
legacy_bdm=legacy_bdm)
根据上面的说明,cctxt.cast 实际为RPCClient的cast函数,如下:
def cast(self, ctxt, method, **kwargs):
if self.server_params:
def cast_to_server(ctxt, msg, **kwargs):
if self.fanout:
return self.proxy.fanout_cast_to_server(
ctxt, self.server_params, msg, **kwargs)
else:
return self.proxy.cast_to_server(
ctxt, self.server_params, msg, **kwargs) caster = cast_to_server
else:
"""caster为ComputeTaskAPI实例的cast方法"""
caster = self.proxy.fanout_cast if self.fanout else self.proxy.cast
"""调用caster方法"""
self._invoke(caster, ctxt, method, **kwargs)
RPCClient中的self.proxy指向处理rpc的代理,这里为ComputeTaskAPI类,说了半天其实创建了RPCClient,但是RPCClient又回来调用API类自身的cast方法。由于继承关系,直接进入nova.openstack.common.rpc.proxy.py中,调用RpcProxy的cast方法。如下:
def cast(self, context, msg, topic=None, version=None):
self._set_version(msg, version)
msg['args'] = self._serialize_msg_args(context, msg['args'])
"""其中rpc为nova.openstack.common.rpc"""
rpc.cast(context, self._get_topic(topic), msg)
进入nova/openstack/common/rpc/__init__.py模块,该模块中包含了RPC调用的接口,如下:
def cast(context, topic, msg):
return _get_impl().cast(CONF, context, topic, msg)
先看_get_impl()函数:
def _get_impl():
global _RPCIMPL
if _RPCIMPL is None:
try:
_RPCIMPL = importutils.import_module(CONF.rpc_backend)
except ImportError:
impl = CONF.rpc_backend.replace('nova.rpc',
'nova.openstack.common.rpc')
_RPCIMPL = importutils.import_module(impl)
return _RPCIMPL
此处rpc_backend为qpid,进入nova/openstack/common/rpc/impl_qpid.py。由于AMQP后端的实现有多种,所以这里对各种后端实现进行封装,对外提供统一的接口。且看cast函数:
def cast(conf, context, topic, msg):
return rpc_amqp.cast(
conf, context, topic, msg,
rpc_amqp.get_connection_pool(conf, Connection))
该函数调用nova/openstack/common/rpc/amqp.py中的cast函数,在amqp.py中主要是抽象地利用底层的实现构建了RPC调用的请求逻辑。
此处, rpc_amqp.get_connection_pool(conf, Connection)可以获取AMQP连接池,这个连接池和具体的AMQP后端实现对应。接着来看rpc_amqp.cast函数,主要内容为从连接池中建立连接,然后使用impl_qpid.py中的Connection连接发送消息。后面的处理过程可以参考:http://blog.csdn.net/gaoxingnengjisuan/article/details/12230521。主要内容就是建立创建TopicPublisher并绑定exchange,然后发送消息。
总结流程图如下:

如果是使用call函数进行RPC调用的话,前面流程与cast函数类似,在此从如下代码开始分析:
def call(conf, context, topic, msg, timeout=None):
"""Sends a message on a topic and wait for a response."""
return rpc_amqp.call(
conf, context, topic, msg, timeout,
rpc_amqp.get_connection_pool(conf, Connection))
接着是偏底层的调用:
nova/openstack/common/rpc/amqp.py
def call(conf, context, topic, msg, timeout, connection_pool):
"""Sends a message on a topic and wait for a response."""
rv = multicall(conf, context, topic, msg, timeout, connection_pool)
# NOTE(vish): return the last result from the multicall
rv = list(rv)
if not rv:
return
return rv[-1]
def multicall(conf, context, topic, msg, timeout, connection_pool):
"""Make a call that returns multiple times.""" LOG.debug(_('Making synchronous call on %s ...'), topic)
msg_id = uuid.uuid4().hex
msg.update({'_msg_id': msg_id})
LOG.debug(_('MSG_ID is %s') % (msg_id))
_add_unique_id(msg)
pack_context(msg, context)
import dbgp
dbgp.brk(__file__)
with _reply_proxy_create_sem:
if not connection_pool.reply_proxy:
connection_pool.reply_proxy = ReplyProxy(conf, connection_pool)#1)创建处理reply消息的direct型consumer、queue和exchange
msg.update({'_reply_q': connection_pool.reply_proxy.get_reply_q()})
wait_msg = MulticallProxyWaiter(conf, msg_id, timeout, connection_pool)#2)创建处理reply消息的waiter(相当于结果集对象)并添加到之前的ReplyProxy对象中
with ConnectionContext(conf, connection_pool) as conn:
conn.topic_send(topic, rpc_common.serialize_msg(msg), timeout)#3)发送消息
return wait_msg
下面用一张图简单看看call函数调用后该如何接收并返回RPC调用结果:

整个过程都是ReplyProxy对象在进行控制处理。其中的消息队列是direct型专门用来接收返回信息的,红色箭头指明了返回信息的数据流向,DirectConsumer监听并从消息队列中取出消息,然后将消息最后转交给MulticallProxyWaiter对象,该对象会作为结果返回,可以迭代并取出内容。注意MulticallProxyWaiter一般会在call函数调用后立即返回,此时其中并没有包含返回的消息结果,所以在迭代取出内容时会进行阻塞,直到DirectConsumer将返回消息取出并放入,此时MulticallProxyWaiter才能继续迭代。
三、额外说明
在消息队列的使用中,最关键的是exchange和topic,其确定了消息将发送至哪个队列,也就确定了消息将由哪个组件的哪个函数处理。所有的nova服务组件启动时都会设置exchange为nova,使用哪个组件的rpcapi.py文件中的类就会将topic初始化为该组件的topic,每个组件的topic具体内容会在/etc/nova/nova.conf中进行配置。这样exchange和topic就共同确定了消息的处理流程!!!
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 核心部 ...
- OpenStack nova VM migration (live and cold) call flow
OpenStack nova compute supports two flavors of Virtual Machine (VM) migration: Cold migration -- mig ...
- OpenStack入门篇(九)之nova服务(控制节点)的部署与测试
1.Nova介绍 Nova是openstack最早的两块模块之一,另一个是对象存储swift.在openstack体系中一个叫做计算节点,一个叫做控制节点.这个主要和nova相关,我们把安装为计算节点 ...
- OpenStack之Nova模块
Nova简介 nova和swift是openstack最早的两个组件,nova分为控制节点和计算节点,计算节点通过nova computer进行虚拟机创建,通过libvirt调用kvm创建虚拟机,no ...
- Openstack Nova 源码分析 — RPC 远程调用过程
目录 目录 Nova Project Services Project 的程序入口 setuppy Nova中RPC远程过程调用 nova-compute RPC API的实现 novacompute ...
- Openstack计算Nova组件
欢迎来到虚拟机的世界,如果我们将Openstack环境里运行在各个无力节点上的各种服务看座生命体,而不是死的指令集合,那么就是一个虚拟机的世界. Openstack的计算组件,也就是Nova项目实现了 ...
- nova创建虚拟机源码分析系列之六 api入口create方法
openstack 版本:Newton 注:博文图片采用了很多大牛博客图片,仅作为总结学习,非商用.该图全面的说明了nova创建虚机的过程,从逻辑的角度清晰的描述了前端请求创建虚拟机之后发生的一系列反 ...
- nova创建虚拟机源码分析系列之七 传入参数转换成内部id
上一篇博文将nova创建虚机的流程推进到了/compute/api.py中的create()函数,接下来就继续分析. 在分析之前简单介绍nova组件源码的架构.以conductor组件为例: 每个组件 ...
随机推荐
- 基于spec探路者团队贪吃蛇作品的评论
1 运动功能 由以上两图贪吃蛇的位置不同可知,运动功能实现.并且我能够通过使用键盘上的上下左右方位键控制蛇的移动方向,蛇在控制的方向上进行直线前进. 2 吃食物功能 以上两图可知吃食物功能实现.当界面 ...
- 探路者 Alpha阶段中间产物
版本控制 git地址:https://git.coding.net/clairewyd/toReadSnake.git 贪吃蛇(单词版)软件功能说明书 1 开发背景 “贪吃蛇”这个游戏对于80, ...
- 04慕课网《vue.js2.5入门》——Vue-cli开发todolist
主要文件目录: 文件代码: 根实例,初始化vue: <!--index.html,网站入口页面,和main.jsp组成一套.vue文件,包含--> <!DOCTYPE html> ...
- OGNL动态实现result
OGNL就是struts.xml文件中的<result>通过get()方法,动态获取action类中的变量 <struts> <package name="de ...
- MacOS下搭建python环境
1. 安装须知 Mac OS自身其实已经带有Python,版本为2.7.X,这个Python主要用于支持系统文件和XCode,所以我们在安装新的Python版本时候最好不要影响这部分. 这里就会出现一 ...
- 【最小生成树+LCA】Imperial roads
http://codeforces.com/gym/101889 I 先跑一遍最小生成树,把经过的边和答案记录下来 对于每个询问的边,显然如果处于MST中,答案不变 如果不在MST中,假设这条边连上了 ...
- Jmeter 快速入门--初识线程组
添加线程组 (1)thread group(线程组),setup thread group相当于lr初始化“环境”的初始化脚本,teardown thread group相当于lr测试完毕后对应的清除 ...
- 设计模式PHP篇(三)————装饰器模式
简单的用php实现了装饰器模式: <?php /** *简单的装饰器模式 */ class PrintText { protected $decorators = []; public func ...
- Binlog的三种模式
binlog模式分三种(row,statement,mixed) 1.Row 日志中会记录成每一行数据被修改的形式,然后在slave端再对相同的数据进行修改,只记录要修改的数据,只有value,不会有 ...
- 利用C#进行文件读写的方法选择总结
小的文本文件(100M以下)直接用File类的ReadAllText()和WriteAllText()方法 这两个方法内部其实就是封装了StreamReader类的ReadToEnd()和Stream ...