Openstack oslo.message rpc簡介


Openstack中幾乎所有的組件都使用MQ作爲消息傳遞的中間件,通過MQ完成了很多協程任務,實現了服務之間的分佈式部署。所以學習Openstack中的MQ模塊可以更好的掌握Openstack組件之間的通信,其中,oslo.message模塊封裝了Openstack中幾乎所有的對MQ的操作,而rpc又是MQ操作中最典型的應用場景,對它的學習很有必要。


Oslo.message 中的重要概念


server(服務器端): 服務器端爲客戶端提供了可用的PRC接口。

client(客戶端): 客戶端負責調用服務器端提供的RPC接口。

exchange(交換):一個包含了各個項目主題(topic)的容器。

topic(主題):一個RPC接口的標識,服務器端在某個主題上監控方法調用,而客戶端在某個主題上調用方法。

namespace(命名空間):服務器端可以在一個主題上暴露多組方法,而每組方法屬於一個命名空間。

method(方法):一個方法由一個名字和一組命名的參數組成。

transport(傳輸工具):一個傳送PRC請求到服務器端並將響應返回給客戶端的底層消息系統。目前常用的transport有 rabbitmq 和qpid。

API version:每個命名空間都有一個版本號,當命令空間的接口變化時,這個版本號也會相應增加。向前兼容的修改只需要更改小版本號,向前不兼容的更改需要更改大版本號。


Oslo.messsage 的典型應用場景


1. Invoke method on one of multiple servers(選擇多個服務器端的一個服務器進行遠程方法調用)

這種情況下,會有多個服務器端在一個exchange和一個topic上監聽方法調用,當客戶在相應的exchange和topic上調用方法時,這個請求將會分發給多個服務器端中的一個服務器進行方法的調用。請求的方式會採用round robin模式。


下面的代碼是這種應用場景在qpid上的實現,首先是服務器端的代碼:

#! /usr/bin/env python

import sys
import time
import logging

from oslo_config import cfg
from oslo import messaging

class TestEndpoint(object):

    def __init__(self, server, target=None):
        self.server = server
        self.target = target

    def methodA(self, ctx, **args):
        print("%s::TestEndpoint::methodA( ctxt=%s arg=%s ) is called"
                    % (self.server, str(ctx),str(args)))

def main():
    url = 'qpid://localhost:5673'
    exchange = 'my-exchange'
    topic = 'my-topic'
    namespace = 'my-namespace'
    argv = sys.argv[1:]
    if argv is None:
        print 'You should specify the server name'
        return -1
    server = argv[0]
    version = '1.1'
    logging.basicConfig(level=logging.INFO)
    transport = messaging.get_transport(cfg.CONF, url=url)
    target = messaging.Target(exchange=exchange,
                              topic=topic,
                              namespace=namespace,
                              server=server,
                              version=version)
    endpoints = [TestEndpoint(server, target)]
    server = messaging.get_rpc_server(transport, target, endpoints, executor='blocking')

    try:
        server.start()
    except KeyboardInterrupt:
        server.stop()
        server.wait()

if __name__ == "__main__":
    sys.exit(main())

接下來是是客戶端的代碼:

#! /usr/bin/env python

import sys
import time
import logging

from oslo_config import cfg
from oslo import messaging

def main(argv=None):
    url = 'qpid://localhost:5673'
    exchange = 'my-exchange'
    topic = 'my-topic'
    namespace = 'my-namespace'
    version = '1.1'
    logging.basicConfig(level=logging.INFO)
    transport = messaging.get_transport(cfg.CONF, url=url)
    target = messaging.Target(exchange=exchange,
                              topic=topic,
                              namespace=namespace,
                              version=version)
    client = messaging.RPCClient(transport, target, version_cap=version)
    test_context = {"application": "my-client",
                    "time": time.ctime(),
                    "cast": False}
    args = {}
    client.call(test_context, 'methodA', **args)
    transport.cleanup()

if __name__ == "__main__":
    sys.exit(main())


確保使用以下的方式啓動qpid和執行代碼:

qpidd --auth no -p 5673  #啓動qpid
python rpc_qpid_server.py my-server01  #啓動server01
python rpc_qpid_server.py my-server02  #啓動server02
python rpc_qpid_client.py  # 發送消息


2. Invoke Method on a Specific Server (指定多個服務器中的一個進行方法的調用)

這種情況下,會有多個服務器端在一個exchange和一個topic上監聽方法調用,客戶在相應的exchange和topic上調用方法並指定具體一個server進行方法調用。

此時只需要修改客戶端中建立target的代碼:

target = messaging.Target(exchange=exchange,
                              topic=topic,
                              <strong>server='my-server01',</strong>
                              namespace=namespace,
                              version=version)

3. Invoke Method on all of Multiple Servers(在所有的服務器中進行方法調用)

此時需要採用fanout的方法,修改客戶端的代碼如下:

    target = messaging.Target(exchange=exchange,
                              topic=topic,
                            <strong>  fanout=True,</strong>
                              namespace=namespace,
                              version=version)


Oslo.message 提供的rpc的方式:

1. cast - 採用異步的方式,沒有結果返回

2. call - 採用同步的方式,會等待結果返回

上面所說的第三個應用場景只能採用cast的方式。


參考文獻: https://wiki.openstack.org/wiki/Oslo/Messaging


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章