oslo_messaging非使用层面的浅析(一)

1 篇文章 0 订阅
1 篇文章 0 订阅

oslo_messaging的浅析(一)

本文不做具体使用到的参数的分析, 具体使用和参数意义直接看官方文档就好,这里借助具体的openstack项目说一下他对rabbitmq的大体封装以及我本人遇到的一些坑(以下所有内容也仅仅基于rabbitmq)。

why?

一定要弄清楚的问题一个就是:直接使用rabbitmq和使用oslo_messaging这个库间接的使用有什么区别。

olso_messaging实际上是在rabbitmq的基础上通过一些列的调用,最终暴露给用户一个简单的使用接口,用户不必关心内部的实现,只用配置好配置文件,进行简单的函数调用即可。
并且由于这个库是openstack的标准库,里面的一些函数命名和默认参数是针对于openstack的概念来讲的。
其实最终暴漏给用户的是两个概念:1.rpc,2.notification

从用户层面来看

rpc

rpc(即远程调用)的概念被划分为调用方和被调用方
调用方称为client:rpc_client
被调用方称为server:rpc_server
使用时,被调用方server.start,等待调用方client.cast 或 clinet.call即可发起阻塞或非阻塞的远程调用。

notification

notification,顾名思义,消息/通知,其概念被分为
通知方:notifier(官方也叫driver), 监听方:notification_listener
使用时,监听方listener.start, 调用方notifier.notfiy(具体暴漏给用户使用时是sample,audit,info等不同level的方法) 即可把消息发给监听方进行处理。

从代码层面来看

rpc
rpc client

当rpc client执行一次远程调用时实际发生了什么呢 ?
(代码在oslo_messaging/rpc/client.py文件里)

首先要实例化RPCClient这个类
在这里插入图片描述
然后执行cast/call方法,最终执行到基类_BaseCallContext里的call/cast方法
在这里插入图片描述
可以看到两者都是执行到了transport._send方法,只有参数不同,这里最大的区别其实是wait_for_reply这个参数,顾名思义wait or no wait也就是我们说的阻塞/非阻塞。
那_send这个方法,最重要的两关键一个是transport本身,一个是target参数,这两个东西是
rpc client __init__的时候必须要传的参数,

transport
是由(osllo_messaging/transport.py文件)_get_transport方法而来
在这里插入图片描述
这里url是配置文件里配的,这里以rabbitmq为例
entry_point到oslo_messaging._drivers.impl_rabbit:RabbitDriver,最终获得到的是RabbitDriver的实例。

target
直接实例化即可
在这里插入图片描述
这里注意到两个参数exchange和topic,和rabbitmq里的exchange和routing_key的概念一致

_send

那我们接着来看 transport._send方法,前面也说到了transport此时是RabbitDriver

在这里插入图片描述
通过代码的得知_send方法其实是在其基类AMQPDriverBase中(oslo_messgaing/_drivers/amqpdriver.py),
查看_send函数的代码,我们只关心以下部分
在这里插入图片描述
在这里插入图片描述

再回顾上面的cast和call函数里调用_send的时候是没有传notify找个参数的,所以这个case一定不成立;那看接下来的两个case,elif target.fanout/else(这里的fanout与rabbitmq本身的fanout意义是一样的)那也就是说我们在生成target或者client.prepare的时候可以通过指定fanout这个参数来决定进入哪个case,(注意第三个case里如果指定了target.server那么topic是target.topic和target.server二者相结合)那我们这里来看一下conn.fanout_send和conn.topic_send这两个方法(conn是__enter__ exit __getattr__的产物,具体本文不细说了,这里只要知道最终调用到了oslo_messaging/_drivers/impl_rabbit.py里Connection这个类就可以了):
conn.fanout_send
在这里插入图片描述
其实到这里基本上就清楚了fanout_send就是往名叫target.topic + "_fanout"这个exchange里发送fanout模式的消息,所有bind到这个exchange的queue都会收到这条消息,如果这个exchange没有创建过,在self._publish方法里会被declare.
conn.topic_send
在这里插入图片描述
topic_send就是以topic做为routing_key 以exchange_name这个参数值命名的exchange里发送topic模式的消息,这里注意区别就是exchange_name是上级调用_get_exchange方法得来的
在这里插入图片描述
_default_exchange如果仔细看的话前面其实前面的截图里有,就是conf.control_exchange
默认是openstack(这里大概知道点为啥oslo_messaging是为openstack搞得了吧😄),关键还是取决于target,如果target里没有指定才会用配置文件的。
同样,如果这个exchange没有创建过,在self._publish方法里会被declare.

rpc server

首先要获得一个rpc server的实例
在这里插入图片描述
同样的,transport和target是必须要有的,获得 rpc sever实例后,rpc server调用start方法
在这里插入图片描述
最终调用到了基类的start方法
在这里插入图片描述
关键如图红色,调用到了transport._listen
在这里插入图片描述
(我这里省略了重复的代码跳跃步骤)
在这里插入图片描述
listen方法实际上关键是执行了三个declare,以下称作:
declare_topic_consumer(1)
declare_topic_consumer (2)
declare_fanout_consumer

declare_topic_consumer(1)
在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述
一目了然,总结来说就是使用target的exchange(默认openstack)做为exchange_name
使用target的topic做为默认的queue_name,然后declare这个exchange和queue,然后将二者bind。

declare_topic_consumer(2)
与declare_topic_consumer(1)的唯一区别是这里使用了target.topic结合target.server做为了默认的queue_name。

declare_fanout_consumer
在这里插入图片描述
与上述两种的区别是,这里的queue_name变成了target.topic+"_fanout_"+uuid
exchange_name变成了target.topic+"_fanout",exchange的type变成了fanout

这里也指定了routing_key ,我觉得应该是没用的。

rpc 总结

server监听
一、
1.由target.exchange或配置文件(openstack为默认值)命名的exchange(type为topic模式)
2.以target.topic做为queue_name
2.以target.topic做为routing_key进行queue和exchange的绑定
二、
1.由target.exchange或配置文件(openstack为默认值)命名的exchange(type为topic模式)
2.以target.topic结合target.server做为queue_name
2.以target.topic结合target.server做为routing_key进行queue和exchange的绑定
三、
1.由target.topic+"_fanout"命名的exchange(type为fanout模式)
2.以target.topic+"_fanout_"+唯一uuid做为queue_name
2.将queue和exchange的绑定

client调用
1.非阻塞调用:client.cast
2.阻塞调用:client.call

通过prepare来改变client的target进行fanout或者指定server的调用

oslo_messaging rpc这么设定有什么好处呢?看下面这几张图就明了了。
假如有一个集群,集群里有三台server,每个server有三个processor,每个processor启动一个rpc server。

配置文件里配置control_exchange为ABC
target的topic指定为ABC

在保证client和server的transport一致的情况下
假设target的topic全都为ABC

一、
在这里插入图片描述
当client发起调用且target不指定server时,rabbitmq的消息经过exchange按照routing_key发送到队列ABC,会被整个集群的所有进程来竞争,且只会被一个进程竞争到,即只在一个进程中执行了远程调用。

二、

在这里插入图片描述

当client发起调用时,指定了target的server时如server1,rabbitmq的消息经过exchange按照routing_key发送到队列ABC_server_1,就只会被server1上的的所有进程来竞争,且只会被一个进程竞争到,即只在一个进程中执行了远程调用。

三、
在这里插入图片描述
当client发送调用时指定了target的fanout为true时,rabbitmq会把消息发送到与之绑定的所有队列,每个队列都有一个进程去消费这条消息,即远程调用发生在所有的进程中。

(未完)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值