oslo.messaging
oslo.messaging
oslo.messaging库为OpenStack各个项目使用RPC和事件通知(Event Notification)提供了一套统一的接口.代码库位于https://github.com/openstack/oslo.messaging,项目主页为https://launchapd.net/oslo.messaging,参考文档在http://docs.openstack.org/developer/oslo.messaging.
为了支持不同的RPC后端实现,oslo.messaging对如下的对象进行了统一:
- 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封装了指定某一个消息最终目的地的所有信息,下表所示为其所具有的属性:
| 参数=默认值 | 说 明 |
| exchange = None | (字符串类型)topic所属的范围,不指定的话默认使用配置文件中的control_exchange选项 |
| topic = None | (字符串类型)一个topic可以用来标识服务器所暴露的一组接口(一个接口包含多个可被远程调用的方法).允许多个服务器暴露同一组接口,消息会以轮循的方式发送给多个服务器中的某一个 |
| namespace = None | (字符串类型)用来标识服务器所暴露的某个特定接口(多个可被远程调用的方法) |
| version = None | (字符串类型)服务器所暴露的接口支持M.N类型的版本号.次版本号(N)的增加表示新的接口向前兼容,主版本号(M)的增加表示新接口和旧接口不兼容.RPC服务器可以实现多个不同的主版本号接口. |
| server = None | (字符串类型)客户端可以指定此参数来要求消息的目的地是某个特定的服务器,而不是一组同属某个topic的服务器中的任意一台. |
| fanout = None | (布尔型)当设置为真时,消息会被发送到同属某个topic的所有服务器上,而不是其中的一台. |
在不同的应用场景下,构造Target对象需要不同的参数:创建一个RPC服务器时,需要topic和server参数,exchange参数可选;指定一个endpoint时,namespace和version是可选的;客户端发送消息时,需要topic参数,其他可选.
- Server
一个RPC服务器可以暴露多个endpoint,每个endpoint包含一组方法,这组方法是可以被客户端通过某种Transport对象远程调用的.创建Server对象时,需要指定Transport,Target和一组endpoint.
- RPC Client
- Notifier
import six
import uuid
from oslo_utils import timeutils {'message_id': six.text_type(uuid.uuid4()), #消息id号
'publisher_id': 'compute.hos1', #发送者id
'timestamp': timeutils.utcnow(), #时间戳
'priority': 'WARN', #通知优先级
'event_type': 'compute.create_instance', #通知类型
'payload': {'instance_id': 12, ...}} #通知内容
- Notification Listener
Notification Listener和Server类似,一个Notification Listener对象可以暴露多个endpoint,每个endpoint包含一组方法.但是与Server对象中的endpoint不同的是,这里的endpoint中的方法对应通知消息的不同优先级.比如:
import oslo_messaging class ErrorEndpoint:
def error(self, ctxt, publisher_id, event_type, payload, metadata):
do_something(payload)
return oslo_messaging.NotificationResult.HANDLED
from oslo_config import cfg
import oslo_messaging as messaging class ServerControlEndpoint(object):
target = messaging.Target(namespace='controle',
version='2.0') def __init__(self, server):
self.server = server def stop(self, ctx):
if self.server:
self.server.stop() class TestEndpoint(object):
def test(self, ctx, arg):
return arg transport = messaging.get_transport(cfg.CONF)
target = messaging.Target(topic='test',
server='server1')
endpoints = [
ServerControlEndpoint(None),
TestEndpoint(),
] server = messaging.get_rpc_server(transport, target, endpoints,
executor='blocking')
server.start()
server.wait()
| 参数=默认值 | 说 明 |
| conf | (oslo.config.cfg.ConfigOpts类型)oslo.config配置项对象 |
| url = None | (字符串或者oslo.messaging.Transport类型)transport URL.如果为空,采用conf配置中的transport_url项所指定的值 |
| namespace = None | (字符串类型)用来标识服务器所暴露的某个特定接口(多个可被远程调用的方法) |
| allowed_remote_exmods = None | (列表类型)Python模块的列表.客户端可用列表里的模块来deserialize异常 |
| aliases = None | (字典类型)transport别名和transport名称之间的对应关系 |
| 参数=默认值 | 说 明 |
| transport | (Transpor类型)transport对象 |
| target | (Target类型)target对象,用来指明监听的exchange,topic和server |
| endpoints | (列表类型)包含了endpoints对象实例的列表 |
| executor='blocking' | (字符串类型)用来指明消息接收和发收的方式:目前支持两种方式: blocking:在这种方式中,用户调用start函数后,在start函数中开始请求处理循环:用户线程阻塞,处理下一个请求.直到用户调用了stop函数后,这个处理循环才会退出.消息的接收和分发处理都在调用start函数的线程中完成. eventlet:在这种方式中,会有一个协程GreenThread来处理消息的接收,然后有其他不同的GreenThread来处理不同消息的分发处理.调用start的用户线程不会被阻塞 |
| serializer = None | (Serializer类型)用来序列化/反序列化消息 |
#client.py 客户端 from oslo_config import cfg
import oslo_messaging as messaging transport = messaging.get_transport(cfg.CONF)
target = messaging.Target(topic='test')
client = messaging.RPCClient(transport, target)
ret = client.call(ctxt={},
method='test',
arg='myarg') cctx = client.prepare(namespace='control', version='2.0')
cctx.cast({}, 'stop')
这里target对象构造时,必须要有的参数只有topic,创建RPCClient对象时,可以接受的参数如下表所示:
| 参数=默认值 | 说 明 |
| transport | (Transport类型)transport对象 |
| target | (Taget类型)该client对象的默认target对象 |
| timeout = None | (整数或者浮点数类型)客户端调用call方法时超时时间(秒) |
| version_cap = None | (字符串类型)最大所支持的版本号.当版本号超过时,会扔出RPCVersionCapError异常 |
| serializer = None | (Serializer类型)用来序列化/反序列化消息 |
| retry = None |
(整数类型)连接重试次数:
None或者-1:一直重试
0:不重试
>0:重试次数
|
远程调用时,需要传入调用上下文,调用方法的名字和传给调用方法的参数.
Target对象的属性在RPCClient对象构造以后,还可以通过prepare()方法修改.可以修改的属性包括exchange,topic,namespace,version,server,fanout,timeout,version_cap和retry.
修改后的target属性只在这个prepare()方法返回的对象中有效.
下面我们再来看一个利用oslo_messaing实现通知消息处理的例子:
#notification_listener.py 消息通知处理 from oslo_config import cfg
import oslo_messaging as messaging class NotificationEndPoint(object):
def warn(self, ctxt, publisher_id, event_type, payload, metadata):
do_something(payload) class ErrorEndpoint(object):
def error(self, ctxt, publisher_id, event_type, payload, metadata):
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()
通知消息处理的endpoint对象和远程过程调用的endpoint对象不同,对象定义的方法要和通知消息的优先级一一对应.我们可以为每个endpoint指定所对应的target对象.
最后调用get_notificaton_listener()函数构造notification listener对象,get_notification_listener()函数的参数如下表所示:
| 参数=默认值 | 说 明 |
| transport | (Transport类型)transport对象 |
| target | (列表类型)target对象的列表,用来指明endpoints列表中的每一个endpoint所侦听处理的exchange和topic |
| endpoints | (列表类型)包含了endpoints对象实例的列表 |
| executor='blocking' | (字符串类型)用来指明消息接收和发收的方式:目前支持两种方式: blocking:在这种方式中,用户调用start函数后,在start函数中开始请求处理循环:用户线程阻塞,处理下一个请求.直到用户调用了stop函数后,这个处理循环才会退出.消息的接收和分发处理都在调用start函数的线程中完成. eventlet:在这种方式中,会有一个协程GreenThread来处理消息的接收,然后有其他不同的GreenThread来处理不同消息的分发处理.调用start的用户线程不会被阻塞 |
| serializer=None | (Serializer类型)用来序列化/反序列化消息 |
| allow_requeue=False | (布尔类型)如果为真,表示支持NotificationResult.REQUEUE |
相对应的发送消息通知的代码如下:
#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',
topic='notifications') notifier2 = notifier.prepare(publisher_id='compute')
notifier2.error(ctxt={},
event_type='my_type',
payload={'content': 'error occurred'})
发送通知消息时,首先要构造Notifier对象,此时可能需要指定的参数如下表所示:
| 参数=默认值 | 说 明 |
| transport | (Transport类型)transport对象 |
| target | (列表类型)target对象的列表,用来指明endpoints列表中的每一个endpoint所侦听处理的exchange和topic |
| publish_id = None | (字符串类型)发送者id |
| driver = None | (字符串类型)后台驱动.一般采用"messaging".如果没有指定,会使用配置文件中的notificaton_driver的值 |
| topic = None | (字符串类型)发送消息的topic.如果没有指定,会使用配置文件中的notification_topics的值 |
| serializer = None | (Serializer类型)用来序列化/反序列化消息 |
初始化Notifier对象的操作比较复杂,所以可以用prepare()方法修改已创建的Notifier对象,prepare()方法返回的是新的Notifier对象的实例.它的参数如下表所示:
| 参数 = 默认值 | 说 明 |
| publish_id = None | (字符串类型)发送者id |
| retry = None |
(整数类型)连接重试次数:
None或者-1:一直重试
0:不重试
>0:重试次数
|
最后可以调用Notifier对象的不同方法(error, critical, warn, 等等)发送不同优先级的消息通知.
oslo.messaging的更多相关文章
- 探索 OpenStack 之(15):oslo.messaging 和 Cinder 中 MessageQueue 消息的发送和接收
前言:上一篇文章 只是 RabbitMQ 的科普,本文将仔细分析 Cinder 中 RabbitMQ 的各组件的使用.消息的发送和接收等.由于各流程步骤很多,本文只会使用若干流程图来加以阐述,尽量做到 ...
- openstack oslo.messaging库
openstack oslo.messaging库 2017年04月13日 22:13:25 li_101357 阅读数:1383 版权声明:本文为博主原创文章,未经博主允许不得转载. https ...
- oslo.messaging 1.8.0 bug fix and blueprint
1366597 由于amqp_auto_delete可配置,但是NotifierPublisher使用的是没有在配置中获取而使用的默认的False,即非auo_delete,因而在用户配置了amqp_ ...
- Neutron Messaging Callback System
callback system 用在进程内部通信,Messaging Callback System是给进程间通信.为了agent不通过RPC就能得到resource的变化. 目前用在: QoS po ...
- openstack中eventlet使用
openstack中使用eventlet的协程来实现并发. 第一种,使用eventlet.GreenPool来管理绿色线程 如l3-agent在开启了8个绿色线程来处理router消息 def _pr ...
- git review出现的问题
在提交代码review的时候可能会出现 Could not connect to gerrit.Enter your gerrit username: xxxxTrying again with ss ...
- [转] OpenStack Kilo 更新日志
OpenStack 2015.1.0 (Kilo)更新日志 原文: https://wiki.openstack.org/wiki/ReleaseNotes/Kilo/zh-hans 目录 [隐藏] ...
- 探索 OpenStack 之(16):计量模块 Ceilometer 介绍及优化
0. 背景 0.1 为什么要有 Ceilometer? 通常云,特别是公有云在计费方面有三个层次: 计量 (Metering): 收集资源的使用数据,其数据信息主要包括:使用对象(what), 使用者 ...
- 探索 OpenStack 之(17):计量模块 Ceilometer 中的数据收集机制
本文将阐述 Ceilometer 中的数据收集机制.Ceilometer 使用三种机制来收集数据: Notifications:Ceilometer 接收 OpenStack 其它服务发出的 noti ...
随机推荐
- 当打开一个.h或.cpp文件时, Solution Explorer就自动展开文件所在的目录
当打开一个.h或.cpp文件时, Solution Explorer就自动展开文件所在的目录: 如果不想展开: Tools -> Options -&g ...
- bzoj 1385: [Baltic2000]Division expression【脑洞】
加括号再去括号就是除变加,显然尽可能多的除变加是最优的,然后发现唯一不能变成乘数的是第二个数,所以把其他数乘起来mod第二个数,如果是0就是YES,否则说明最后不能除尽,就是NO #include&l ...
- IT兄弟连 JavaWeb教程 Servlet表单乱码问题
在使用原生的Servlet进行Web应用开发时经常会遇到一些中文乱码问题,造成乱码问题的原因只有一个:即客户端与服务端的字符编码不一致所导致的. 请求参数乱码问题 服务器端获取客户端传递过来的数据出现 ...
- print打印
print打印输出的优点是简单直接粗暴有效,就是用print()把可能有问题的变量打印出来看看缺点是将来还得删掉它,想想程序里到处都是print(),运行结果也会包含很多垃圾信息 __________ ...
- (023) 关于51单片机的A5指令
可看见一篇讲51单片机加密的文章这么讲: [加密方法:在A5后加一个二字节或三字节操作码,因为所有反汇编软件都不会反汇编A5指令,造成正常程序反汇编乱套,执行程序无问题仿制者就不能改变你的源程序.] ...
- [未读]JavaScript高效图形编程
去年买来就一直搁置,因为是js游戏相关,暂时还用不到.
- webpack采坑十连跳
4.css.js一同打包进html ---------------- https://www.cnblogs.com/amiezhang/p/9723565.html 依赖内联插件 HtmlWebp ...
- AJPFX总结OpenJDK 和 HashMap大量数据处理时,避免垃圾回收延迟的技巧二
HashMap简史 “Hash Code”这个概念第一次出现是在1953年1月的<Computing literature>中,H. P. Luhn (1896-1964) 在一篇 IB ...
- hadoop的安装和配置
hadoop安装 在Apache Hadoop主页的下载页面https://hadoop.apache.org/releases.html选择版本进行下载: 下载下来的是压缩包: 将压缩包使用Xftp ...
- datetime 模块详解
1.import datetime 常用方法: ttimedelta() 括号里默认为days,进行别的单位运算可以加上如hours = 1这样.除了进行减法运算,还可以进行加法运算. >> ...