《OpenStack开源云—王者归来》PRC调用学习笔记

来源:互联网 发布:淘宝网货源怎么找 编辑:程序博客网 时间:2024/06/05 18:24

RPC调用

RPC采用AMQP协议实现通信,在OpenStack中,采用RabbitMQ作为消息队列。

RabbitMQ的三个重要组件:交换机(exchange)、队列(queue)和绑定(binding)。有关RabbitMQ的入门级材料,可以参考链接http://blog.ftofficer.com/2010/03/translation-rabbitmq-python-rabbits-and-warrens/

 

目前有许多工具包实现了与RabbitMQ的交互,在OpenStack中,默认的工具包是kombu包3。本文的代码来源于《OpenStack开源云—王者归来》的第11章给出的例子。该代码是仿造Nova中的rpc模块2。代码可以通过下面的链接获取到:

http://github.com/JiYou/openstack/blob/master/chap11/RPC

 

 

下面结合代码看一下在OpenStack中的rpc调用过程,以下理解是源于书本,但加入了一些自己的分析。

1.      调用流程

首先看一下调用流程图,在OpenStack中共有rpc.call和rpc.cast两种调用方式。其中rpc.call比较复杂,需要获取返回值。这种调用需要用到topicexchange和directexchange,前者用于客户端想服务器发送rpc请求;后者用于服务器向客户端返回rpc调用结果。而rpc.cast则不需要返回值,只需要用到topicexchange,如下图中红色虚线框所示。

RPC远程调用流程

2.      代码包含的Python文件及其简单说明

文件名

描述

server.py

服务器端的 启动脚本

service.py

接收rpc请求;创建与RabbitMQ的连接,创建分发器,创建消费者和激活消费者

impl_kombu.py

核心代码。实现了消费者和生产者,创建交换器、绑定和队列

rpc_ampq.py

处理rpc请求并负责请求结果的返回

dispatcher.py

将客户端的请求分发给相应的方法去处理

manager.py

定义了处理rpc请求的方法

rpc.py

为外界提供API

client.py

RPC调用请求客户端启动脚本

 

3.      代码实现分析

1)     服务器端启动RPC服务(该脚本定义在server.py中)


上面的代码创建了一个Service对象,并且调用该对象的start方法启动rpc服务,调用drain_event方法监听rpc请求。Service类定义在service.py中,代码如下:


初始化方法主要定义了topic和manager两个成员变量。topic其实就是主题交换机的名字,客户端向主题交换机发送请求的时候,应该将消息发送到名为‘sendout_request’的主题交换机中。指定交换器时,名字必须是‘sendout_request’,如果不一致的话就不可能成功完成rpc调用。另外manager对象用于定义处理rpc请求的方法。

start方法首先创建与RabbitMQ的连接,这里比较好理解。详细参考impl_kombu.py中定义的Connection类。

接下来比较重要的是调用create_consumer方法,这个方法有两个参数。一个是主题交换器的主题(我简单的理解就是主题交换器的名字),另外一个是RpcDispatcher对象。上图14行,创建了一个会将消息分发给manager对象去处理的分发器。RpcDispatcher定义在dispatcher.py中,代码如下所示:


接下来,顺着程序的执行,我们来看create_consumer的定义,该方法定义在impl_kombu.py的Connection类中。代码如下:


该方法首先创建了一个ProxyCallback对象,其中proxy是一个RpcDispatcher对象,通过上面对service的分析,我们知道在Service类中,创建了一个分发器,初始化时定义了这个分发器会将消息分发给manager对象去处理。这里RPC请求的处理方法是通过回调函数的机制实现的,关于回调函数我也是第一次接触到,在百度百科里http://baike.baidu.com/view/414773.htm是这么解释的:


在这个例子里,我是这么理解的,首先在初始化RpcDispatcher和ProxyCallback的时候,会将RpcDispatcher指向一个manager对象,然后将ProxyCallback指向已经一个RpcDispatcher对象,这个在上面的分析中可以看出来。然后当消费者接收到消息,触发一个消息处理任务时,会去调用ProxyCallback对象来处理消息,然后ProxyCallback对象会调用RpcDispatcher对象,RpcDispatcher对象最终调用manager对象来处理消息。

 然后,我们接着往下看这个消息处理是如何触发的。declare_topic_consumer方法调用了declare_consumer方法,declare_consumer方法定义如下:


在declare_consumer方法中,创建了一个主题消费者,代码中的consumer_cls为主题消费者,即TopicConsumer类。TopicConsumer类在初始化时,会创建一个主题交换器,代码如下:


然后通过super函数调用其父类ConsumerBase类的__init__方法,在该方法中,会创建一个队列,并且通过routing_key将交换器和创建的队列进行绑定。代码如下:


至此,创建消费者的代码全部完毕。也就是service中start方法的语句self.conn.create_consumer(self.topic,rpc_dispatcher)执行完毕。接着往下执行,通过self.conn.consume()激活消费者,该方法最终会调用ConsumerBase类中consume方法,ConsumerBase.consume方法的_callback内部方法会调用一个ProxyCallback的对象来处理消息。代码如下:


代码中callback为一个ProxyCallback对象。整个RPC请求回调函数的调用关系图如下:


§ ConsumerBase对象consume方法的_callback内部方法的功能是获取RPC消息中的消息体,然后将消息交给ProxyCallback对象处理。

§ ProxyCallback对象的功能是解析消息体中的调用方法和参数列表,然后交给RpcDispatcher对象处理。

§ RpcDispatcher对象的功能是调用manager对象的相应方法处理RPC消息。

§ Manager对象定义了处理RPC请求的各种方法。

另外,ProxyCallback对象在处理RPC请求的同时,会调用direct_send方法将处理结果发送给直接交换机。

 

2)     客户端发送RPC请求

相比服务器端,客户端的代码比较好理解,rpc.call方法调用了impl_kombu.call方法,该方法主要实现了两个功能,

o  创建和申明直接消费者,用来接收返回的结果。

o  向主题交换器发送RPC请求。

代码如下:

 

 

0 0
原创粉丝点击