首先给出OpenStack的RPC通信的代码调用架构。
OpenStack消息通信架构图
OpenStack层封装call和cast接口用于远程调用RPC的server上的方法,这些方法都是构造RPC的server的endpoints内的方法。远程调用时,需要提供一个字典对象来指明调用的上下文,调用方法的名字和传递给调用方法的参数(用字典表示)。如:
cctxt =self.client.prepare(vesion=’2.0’)
cctxt.cast(context,‘build_instances’, **kw)
通过cast方式的远程调用,请求发送后就直接返回了;通过call方式远程调用,需要等响应从服务器返回。
下面我们介绍RPC-server和PRC-client的创建,以及对cast和call的远程调用。
-------------------------------------------------- RPC-server.py-----------------------------------------
fromoslo_config import cfg
importoslo_messaging
importtime
classServerControlEndpoint(object):
target =oslo_messaging.Target(namespace='control',
version='2.0')
def __init__(self, server):
self.server = server
def stop(self, ctx):
print“------ServerControlEndpoint. stop --------”
if self.server:
self.server.stop()
classTestEndpoint(object):
def test(self, ctx, arg):
print“------ TestEndpoint.test --------”
return arg
transport= oslo_messaging.get_transport(cfg.CONF)
#从cfg对象中,读取transport_url,rpc_backend和control_exchange信息构
#造Transport对象,其中rpc_backend和control_exchange的默认值分别为:
#’rabbit’和’openstack’。
target= oslo_messaging.Target(topic='test', server='server1')
#在构造RPC-server的target时,需要topic和server参数,exchange参数可
#选。
endpoints= [
ServerControlEndpoint(None),
TestEndpoint(),
]
#一个RPC-server可以暴露多个endpoint,每个endpoint包含一组方法,这组
#方法可以被RPC-client通过某种Transport对象远程调用。
server= oslo_messaging.get_rpc_server(transport, target, endpoints,
executor='blocking')
#构造RPC-server对象,其中executor有两种方式:blocking和eventlet。
#blocking:用户调用start函数后,在start函数中开始请求处理循环,用户线程
#阻塞,处理下一个请求。直到用户调用了stop函数后,这个处理循环才退出。
#消息的接受和分发处理都在调用start函数的线程中完成的。
#eventlet:在这种方式中,会有一个协程GreenThread来处理消息的接收,然后
#有其他不同二屌GreenThread来处理不同消息的分发处理。调用start的用户
#线程不会被阻塞。
#在这里我们使用blocking方式。
try:
server.start()
while True:
time.sleep(1)
exceptKeyboardInterrupt:
print("Stopping server")
server.stop()
server.wait()
------------------------------------------------------------ RPC-client.py --------------------------------------------
fromoslo_config import cfg
importoslo_messaging as messaging
transport= messaging.get_transport(cfg.CONF)
target= messaging.Target(topic='test')
#在构造RPC-client的target时,需要topic参数,其他可选。
client= messaging.RPCClient(transport, target)
ret= client.call(ctxt = {},
method = 'test',
arg = 'myarg')
#远程调用时,需要提供一个字典对象来指明调用的上下文,调用方法的名字和传
#递给调用方法的参数(用字典表示)。
cctxt= client.prepare(namespace='control', version='2.0')
#prepare函数用于修改RPC-client对象的Target对象的属性。
cctxt.cast({},'stop')
[root@jun python]# python oslo_server.py
由于这里Transport采用rabbit的方式,所以可使用rabbitmqctl命令查询相关信息。此时执行oslo_server.py的进程处于阻塞状态等待消息的到来。
[root@jun python]# rabbitmqctl list_consumers | grep test
test <[email protected]> 1 true 0 []
test.server1 <[email protected]> 2 true 0 []
test_fanout_1064b7923baf4d4b9e4e56329f079c12 <[email protected]> 3 true 0 []
执行pythonoslo_client.py后,处于阻塞的oslo_server.py的进程打印信息。
[root@jun python]# python oslo_server.py
------ TestEndpoint.test --------
------ ServerControlEndpoint. stop --------
总结:今天主要介绍了RPC-server和RPC-client的构建,其中涉及call和cast接口的使用。OpenStack正是主要通过这两个接口进行远程调用RPC-server上的方法的。后面几篇文章我们将结合OpenStack源码具体分析RPC-server和RPC-client的使用。