模仿OpenStack寫本身的RPC

 

在openstack中使用兩種通訊方式,一種是Restful API,另外一種是遠程過程調用RPC。本片文章主要講解openstack中RPC的使用方式,以及如何在咱們本身的架構中使用RPC。html

在我前面的一篇文章《基於Rabbitmq的RPC調用》中已經簡單的介紹過RPC,Rabbitmq兩種技術,openstack中的RPC調用實現是本身的通用庫oslo_message,該庫是對基於Rabbitmq實現的RPC的一個封裝。api

 

 1、技術介紹瀏覽器

nova模塊是openstack中最核心的服務,nova模塊使用了衆多的RPC服務將業務解耦,如:nova-api; nova-conductor; nova-scheduler; nova-compute等。每個服務都是一個RPC的服務端,同時每個服務都是一個RPC的客戶端。服務器

service服務啓動的就是nova的RPC服務多線程

 

nova各個服務啓動時就是開啓了一個RPC的服務端,在調用其餘服務時會建立一個客戶端,經過客戶端調用到相應的服務。以nova建立虛擬機爲例,在上圖的第三步中,nova-scheduler選擇好計算節點,將建立虛擬機的信息經過RPC發送給計算節點。代碼通過RPC客戶端的封裝和調用,本文的重點就是如何調用RPC客戶端。
 架構

 

cctxt = self.client.prepare(version=version)

cctxt.cast(context,'select_destinations',**kw)

裏的client是 rpc.get_client(target,serializer=serializer),見下圖。函數

 

經過查找rpc的導入路徑,能夠發現rpc是從nova模塊中導入。url

 

 rpc.py 在get_client函數中,返回了messaging的調用。
spa

 

 

這裏的messaging就是來自oslo_messaging庫。命令行

 

從rpc.py中可知,客戶端來自messaging,其實就是oslo_messaging。因此可以看出openstack中RPC的實現封裝在oslo_messagin庫當中。

oslo_messaging其內部的實現暫時先無論,咱們已經知道了調用其接口就能駕馭這個已經封裝好的oslo_messaging庫來完成本身的一些功能。下面就模擬openstack使用oslo_messaging來完成本身的功能。

 

2、代碼移植

要使用oslo_messagin封裝好的RPC,主要步驟分爲以下幾步:

  1. 安裝oslo_messaging庫
  2. 安裝rabbitmq消息隊列
  3. 建立消息隊列用戶名
  4. 設置用戶權限
  5. 建立配置文件
  6. 調用oslo_messaging中客戶端,服務器端
  7. 啓動服務

 

一、安裝oslo_messaging庫

pip install oslo_messaging oslo_config

二、安裝rabbitmq

apt-get install rabbitmq-server

三、建立消息隊列用戶名

rabbitmqctl add_user openstack stack2018

四、設置權限

rabbitmqctl set_permissions openstack ".*" ".*" ".*"

其中步驟2,步驟3,步驟4對很對讀者來講確定十分眼熟,不錯,流程和openstack安裝Message queue是同樣同樣的。

五、建立配置文件

my.conf

[DEFAULT] url = 'rabbit://openstack:stack2018@127.0.0.1:5672/'

 用戶名:openstack ,密碼:stack2018

 

六、調用oslo_messaging,完成客戶端和服務器端

oslo_message_server.py

#coding:utf-8

from oslo_config import cfg
import oslo_messaging
import time
 
class ServerControlEndpoint(object):
 
    def __init__(self, server):
        self.server = server
 
    def stop(self, ctx):
        if self.server:
            self.server.stop()
 
class AddEndpoint(object):
 
    def add(self, ctx, a,b):
        print 'revice message'
        return a+b

#從配置文件中加載transport_url。在openstack中,帳號、密碼、端口號等都是從配置文件中讀取,支持可配置的。
#配置文件的內容經過oslo_config庫讀取。
opts = [
    cfg.StrOpt('url', default='0.0.0.0'),
]

CONF = cfg.CONF
CONF.register_opts(opts)

CONF(default_config_files=['my.conf'])

#transport_url是指定實現RPC的底層技術,可使rabbitmq,也能夠是別的技術
#從my.conf文件中讀取到該URL。
transport_url = CONF.url

transport = oslo_messaging.get_transport(cfg.CONF,transport_url) 

#target用來指定該rpc server監聽在哪些隊列上。
#target指定了2個參數:topic和server。
target = oslo_messaging.Target(topic='test', server='server1')

#可供別人調用的方法類
endpoints = [
    ServerControlEndpoint(None),
    AddEndpoint(),
]

#建立Server對象時,須要指定Transport、Target和一組endpoint
server = oslo_messaging.get_rpc_server(transport, target, endpoints,
                                       executor='blocking')
try:
    server.start()
    print 'The Server!'
    while True:
        time.sleep(1)
except KeyboardInterrupt:   
    print("Stopping server")
 
server.stop()

 

service文件中使用兩個openstack通用庫,除了oslo_messaging以外,還有一個oslo_config。首先說oslo_config,這個庫的主要功能是從配置文件或者命令行中讀取特定信息。在openstack的安裝過程當中,須要配置各類參數,例如nova.conf中配置rabbitmq。

一樣,咱們在配置文件中也配置了transport_url,經過oslo_config讀取配置的值。下面的client也是同樣,經過oslo_config讀取配置信息。另一個就是主角oslo_messaging的調用。建立一個RPC的服務端,須要四個參數,分別是:

  1. transport
  2. target
  3. endpoints
  4. executor

他們的功能分別是:

  1. transport        RPC功能的底層實現方法,這裏是rabbitmq的消息隊列的訪問路徑
  2. target             指定RPC topic交換機的匹配信息和綁定主機
  3. endpoints      是可供別人遠程調用的方法,也是RPC中的遠程函數
  4. executor        服務的運行方式,單線程或者多線程

經過這四個參數,造成一個可調用的RPC服務端,服務以阻塞的方式在後臺運行。

 

oslo_message_client.py

#coding:utf-8

from oslo_config import cfg
import oslo_messaging

opts = [
    cfg.StrOpt('url', default='helloworld'),
]

CONF = cfg.CONF
CONF.register_opts(opts)

CONF(default_config_files=['my.conf'])

transport_url = CONF.url

 
transport = oslo_messaging.get_transport(cfg.CONF,transport_url)  
target = oslo_messaging.Target(topic='test')  
client = oslo_messaging.RPCClient(transport, target)  
r = client.call({}, 'add', a=2,b=3)
print 'result :',r

#Target對象的屬性在RPCClient對象構造以後,還能夠經過prepare()方法修改,
#能夠修改的屬性包括exchange,topic,namespace,version,server,fanout和retry。
#修改後的target屬性只在這個prepare()方法返回的對象中有效。

cctxt = client.prepare(version='1.0')
r_two = cctxt.call({},'add',a=2,b=3)
print 'result_two :',r_two

 

客戶端調用了oslo_messaging.RPCClient()方法,這個方式就是openstack調用oslo_messaging庫的方法。經過傳入參數:transport:消息處理的端點;target:消息隊列中topic的路由關鍵字,可以準肯定位到要發送的消息隊列的。另外若是建立的client客戶端是共用的,而具體使用時還要修改本身的特性的話,可使用client.prepare這個方法來修改client的參數。例如代碼中使用該方法修改了client的版本號。這樣和openstack的代碼就是保持了一致。

七、開啓服務

先開啓服務器

運行客戶端,調用遠程函數

 

一次RPC的遠程調用就完成了,同時這也是貼近openstack源碼的RPC使用方式,很方便在本身的架構中移植這種現有的技術。

 

 

最後還有一個小彩蛋。在安裝rabbitmq的主機上,進入路徑   cd /usr/lib/rabbitmq/bin/,而後執行命令

 

rabbitmq-plugins enable rabbitmq_management

 

 在瀏覽器中進入地址 http://localhost:15672,使用帳號 guest/guest 登陸,能打開rabbitmq的監控界面。

 

原文出處:https://www.cnblogs.com/goldsunshine/p/10205058.html

相關文章
相關標籤/搜索