首先給出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的使用。