基础知识:
参考博客:http://blog.youkuaiyun.com/happyAnger6/article/details/54777429
- Transport
Transport(传输层)主要实现RPC底层的通信(比如socket)以及事件循环,多线程等其他功能.可以通过URL来获得不同transport的句柄.URL的格式为:
transport://user:password@host:port[,hostN:portN]/virtual_host
目前支持的Transport有rabbit,qpid与zmq,分别对应不同的后端消息总线.用户可以使用oslo.messaging.get_transport函数来获得transport对象实例的句柄.
- Target
Target封装了指定某一个消息最终目的地的所有信息
- Endpoint
Endpoint包含一组方法,这组方法是可以被客户端远程调用的.
- Server
一个RPC服务器可以暴露多个endpoint,每个endpoint包含一组方法,这组方法是可以被客户端通过某种Transport对象远程调用的.创建Server对象时,需要指定Transport,Target和一组endpoint.
- RPC Client
RPC-server和PRC-client举例
rpc_server.py
from oslo_config import cfg
import oslo_messaging as messaging
from oslo_messaging.rpc import dispatcher
class ServerControlEndpoint(object):
target = 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()
return "stop return"
class TestEndpoint(object):
def test(self, ctx, arg):
print "------ TestEndpoint.test --------"
print "arg:", arg
return arg
transport = messaging.get_transport(cfg.CONF)
target = messaging.Target(topic='test',
server='server1')
endpoints = [
ServerControlEndpoint(None),
TestEndpoint(),
]
access_policy = dispatcher.DefaultRPCAccessPolicy
server = messaging.get_rpc_server(transport, target, endpoints,
executor='threading',
access_policy=access_policy)
server.start()
server.wait()
from oslo_config import cfg
import oslo_messaging as messaging
transport = messaging.get_transport(cfg.CONF)
target = messaging.Target(topic='test', server='server1')
client = messaging.RPCClient(transport, target)
ret = client.call(ctxt={},
method='test',
arg='myarg1')
client.call({}, 'test', arg='myarg2')
#client.call({}, 'stop')
cctx = client.prepare(namespace='control', version='2.0')
cctx.cast({}, 'stop')
cctx.call({}, 'stop')
运行rpc_server.py
运行rpc_client.py:
去掉rpc_cleint.py里面的注释
from oslo_config import cfg
import oslo_messaging as messaging
transport = messaging.get_transport(cfg.CONF)
target = messaging.Target(topic='test', server='server1')
client = messaging.RPCClient(transport, target)
ret = client.call(ctxt={},
method='test',
arg='myarg1')
client.call({}, 'test', arg='myarg2')
client.call({}, 'stop')
cctx = client.prepare(namespace='control', version='2.0')
cctx.cast({}, 'stop')
cctx.call({}, 'stop')
修改rpc_client.py
from oslo_config import cfg
import oslo_messaging as messaging
transport = messaging.get_transport(cfg.CONF)
target = messaging.Target(topic='test', server='server1', namespace='control', version='2.0')
client = messaging.RPCClient(transport, target)
client.call({}, 'stop')
cctx = client.prepare(namespace='control', version='2.0')
cctx.cast({}, 'stop')
cctx.call({}, 'stop')
client.call({}, 'test', arg='myarg2')
修改rpc_client.py
from oslo_config import cfg
import oslo_messaging as messaging
transport = messaging.get_transport(cfg.CONF)
target = messaging.Target(topic='test', namespace='control', version='2.0')
client = messaging.RPCClient(transport, target)
client.call({}, 'stop')
cctx = client.prepare(namespace='control', version='2.0')
cctx.cast({}, 'stop')
cctx.call({}, 'stop')
运行rpc_client.py
小结:
(1)rpc_client想要正确调用rpc_server里面endpoint的方法,需要正确设置RPCClient的target的topic、namespace、version等信息。
(2)RPCClient的target里面的server参数:(字符串类型)客户端可以指定此参数来要求消息的目的地是某个特定的服务器,而不是一组同属某个topic的服务器中的任意一台.
(3)Target对象的属性在RPCClient对象构造以后,还可以通过prepare()方法修改.可以修改的属性包括exchange,topic,namespace,version,server,fanout,timeout,version_cap和retry.
- Notification Listener
- Notifier
Notification_listener和Notifier_send举例
notification_listener.py
from oslo_config import cfg
import oslo_messaging as messaging
def do_something(payload):
print "recieve:", payload
class NotificationEndPoint(object):
def warn(self, ctxt, publisher_id, event_type, payload, metadata):
do_something(payload)
def error(self, ctxt, publisher_id, event_type, payload, metadata):
do_something("In NotificationEndPoint")
do_something(payload)
class ErrorEndpoint(object):
def error(self, ctxt, publisher_id,event_type, payload, metadata):
do_something("In ErrorEndpoint")
do_something(payload)
transport = messaging.get_transport(cfg.CONF)
targets = [
messaging.Target(topic='notifications'),
messaging.Target(topic='notifications_bis')
]
endpoints = [
NotificationEndPoint(),
ErrorEndpoint(),
]
listener = messaging.get_notification_listener(transport,
targets,
endpoints)
listener.start()
listener.wait()
from oslo_config import cfg
import oslo_messaging as messaging
transport = messaging.get_transport(cfg.CONF)
notifier = messaging.Notifier(transport,
driver='messaging',
topics=['notifications', 'notifications_bis'])
notifier2 = notifier.prepare(publisher_id='compute')
notifier2.error(ctxt={},
event_type='my_type',
payload={'content': 'error occurred'})
运行notification_listener.py
运行notifier_send.py
修改notifier_send.py
from oslo_config import cfg
import oslo_messaging as messaging
transport = messaging.get_transport(cfg.CONF)
notifier = messaging.Notifier(transport,
driver='messaging',
topics=['notifications'])
notifier2 = notifier.prepare(publisher_id='compute')
notifier2.error(ctxt={},
event_type='my_type',
payload={'content': 'error occurred'})
运行notifier_send.py
修改notifier_send.py
from oslo_config import cfg
import oslo_messaging as messaging
transport = messaging.get_transport(cfg.CONF)
notifier = messaging.Notifier(transport,
driver='messaging',
topics=['notifications'])
notifier2 = notifier.prepare(publisher_id='compute')
notifier2.error(ctxt={},
event_type='my_type',
payload={'content': 'error occurred'})
notifier.error(ctxt={},
event_type='my_type',
payload={'content2': 'error occurred'})
notifier2.warn(ctxt={},
event_type='my_type',
payload={'content': 'warn occurred'})
notifier2.info(ctxt={},
event_type='my_type',
payload={'content': 'info occurred'})
运行notifier_send.py
小结:
(1)发送通知方构造的messaging.Notifier,里面的topics参数指定了一个列表,表示要发生到远程多个的topic。
(2)通知消息监听方的endpoints,如果都实现了某一级别的方法(比如:error),则都是被调用。