源码版本: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与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. OpenStack nova VM migration (live and cold) call flow

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

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

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

  5. OpenStack之Nova模块

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

  6. Openstack Nova 源码分析 — RPC 远程调用过程

    目录 目录 Nova Project Services Project 的程序入口 setuppy Nova中RPC远程过程调用 nova-compute RPC API的实现 novacompute ...

  7. Openstack计算Nova组件

    欢迎来到虚拟机的世界,如果我们将Openstack环境里运行在各个无力节点上的各种服务看座生命体,而不是死的指令集合,那么就是一个虚拟机的世界. Openstack的计算组件,也就是Nova项目实现了 ...

  8. nova创建虚拟机源码分析系列之六 api入口create方法

    openstack 版本:Newton 注:博文图片采用了很多大牛博客图片,仅作为总结学习,非商用.该图全面的说明了nova创建虚机的过程,从逻辑的角度清晰的描述了前端请求创建虚拟机之后发生的一系列反 ...

  9. nova创建虚拟机源码分析系列之七 传入参数转换成内部id

    上一篇博文将nova创建虚机的流程推进到了/compute/api.py中的create()函数,接下来就继续分析. 在分析之前简单介绍nova组件源码的架构.以conductor组件为例: 每个组件 ...

随机推荐

  1. Scrum立会报告+燃尽图(Beta阶段第二周第六次)

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2414 项目地址:https://coding.net/u/wuyy694 ...

  2. 20181009-3 Scrum立会报告+燃尽图02

    此作业要求:[https://edu.cnblogs.com/campus/nenu/2018fall/homework/2190] 一.小组介绍 组长:王一可 组员:范靖旋,王硕,赵佳璐,范洪达,祁 ...

  3. Python:字典操作总结

     字典是Python中唯一的映射类型 [注]:字典中数据是无序排放的 一.字典的创建方法 方法1:用大括号包裹键值对从而创建字典 addict={}#创建一个空字典 addict={key1:valu ...

  4. 遇到Intel MKL FATAL ERROR: Cannot load libmkl_avx2.so or libmkl_def.so问题的解决方法

    运行一个基于tensorflow的模型时,遇到Intel MKL FATAL ERROR: Cannot load libmkl_avx2.so or libmkl_def.so问题. 解决方法:打开 ...

  5. Alpha-7

    前言 失心疯病源7 团队代码管理github 站立会议 队名:PMS 530雨勤(组长) 今天完成了那些任务 18:30~20:30 通过统计法来得出人车团块的区别和鉴别方法,然而效果并不显著 代码签 ...

  6. PXE Centos7和Centos6

    外网网卡:192.168.23.10, 内网网卡:192.168.10.2 PXE(preboot execute environment,预引导执行环境)是由Intel公司开发的最新技术,工作于Cl ...

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

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

  8. Java实现的词频统计——功能改进

    本次改进是在原有功能需求及代码基础上额外做的修改,保证了原有的基础需求之外添加了新需求的功能. 功能: 1. 小文件输入——从控制台由用户输入到文件中,再对文件进行统计: 2.支持命令行输入英文作品的 ...

  9. url传带有汉字的参数乱码解决

    url传带有汉字的参数乱码解决 var reg = new RegExp("(^|&)createName=([^&]*)(&|$)"); var r = ...

  10. Centos上Apache重启,mysql重启,nginx重启方法

    转载:http://www.3lian.com/edu/2012/04-01/24278.html Centos上Apache重启,mysql重启, nginx 重启方法 1.重启 apache se ...