本文目录一览:
- 1、如何通过IP访问并运行服务器上的python文件
- 2、python怎么经过protobuf完成rpc
- 3、Electron 框架中调用 Python 构建桌面应用
- 4、微服务跨语言调用(摘选)
- 5、从 0 到 1:全面理解 RPC 远程调用
如何通过IP访问并运行服务器上的python文件
很多种方法,例如:
rpc远程调用.通过ip地址,远程指定python文件,直接调用
写一个简单的socket,进行通信,发送命令,根据命令启动python文件
通过http协议,建立简单的web服务,通过http请求调用
通过消息队列,例如zmq,rabbitmq,amq,发送消息或者命令,由消费者调用python文件.
python怎么经过protobuf完成rpc
客户方像挪用当地办法同样去挪用长途接口办法,RPC 结构供给接口的署理完成,理论的挪用将拜托给署理RpcProxy
。署理封装挪用资讯并将挪用转交给RpcInvoker 去理论履行。在客户真个RpcInvoker 经过衔接器RpcConnector
去保持与效劳端的通道RpcChannel,并运用RpcProtocol
履行协定编码(encode)并将编码后的恳求音讯经过通道发送给效劳方。RPC 效劳端接纳器 RpcAcceptor
接纳客户真个挪用恳求,一样运用RpcProtocol 履行协定解码(decode)。解码后的挪用资讯传送给RpcProcessor
去掌握处置挪用进程,末了再拜托挪用给RpcInvoker 去理论履行并前往挪用后果。
protobuf
rpc在下面组件中首要表演RpcProtocol的人物,使得咱们省去了协定的描绘,而且protobuf协定在编码和时间效力都是上十分高效的,这也是许多公司选用protobuf作为数值序列化和通讯协议的起因。一起protobuf
rpc界说了一个笼统的rpc结构,以下图所示:
RpcServiceStub和RpcService类是protobuf编译器依据proto界说天生的类,RpcService界说了效劳端表露给客户真个函数接口,详细完成需求用户本人担当这个类来完成。RpcServiceStub界说了效劳端表露函数的描绘,并将客户端对RpcServiceStub中函数的挪用同一转换到挪用RpcChannel中的CallMethod办法,CallMethod经过RpcServiceStub传过去的函数描绘符和函数参数对该次rpc挪用停止encode,最后经过RpcConnecor发送给效劳方。自己以客户端相反的进程最后挪用RpcSerivice中界说的函数。现实上,protobuf
rpc的结构仅仅RpcChannel中界说了空的CallMethod,以是详细怎么样停止encode和挪用RpcConnector都要本人完成。RpcConnector在protobuf中没有界说,以是这个完结由用户本人完成,它的效果那是收发rpc音讯包。在效劳端,RpcChannel经过挪用RpcService中的CallMethod来详细挪用RpcService中表露给客户真个函数。
引见了这么多,关于怎样用protobuf rpc来完成一个rpc确定仍是一头雾水吧,下面就用protobuf rpc来完成一个简略的python版rpc demo吧。
下面间接给出demo描绘PRC的proto文件,至于proto文件的编写规定能够参考protobuf官网。
common.proto文件:
package game;
message RequestMessage
{
required string message = 1;
}
message ResponseMessage
{
required string message = 1;
}
game_service.proto文件:
package game;
import "common.proto";
option py_generic_services = true;
service GameService
{
rpc connect_server(RequestMessage) returns(RequestMessage);
}
common.proto文件描绘了RPC中收发的音讯;game_service.proto描绘了效劳器导出的connect_server函数,该函数承受RequestMessage目标作为参数,并前往RequestMessage目标。在运用PRC协定时,必需加之option
py_generic_services =
true;可选项,要否则编译器不会天生蕴含connect_server函数的GameService描绘。
运用编译器protoc编译proto文件,详细号令为:
protoc.exe --python_out=. game_service.proto
编译后天生的文件为game_service_pb2.py,该文件首要是完成了GameService和GameService_Stub类。GameService_Stub类用于客户端挪用者来挪用GameService的效劳。
后面曾经说了,在客户端,RpcChannel只完成了一个空的CallMethod,以是需求担当RpcChannel从新这个函数来encode音讯和发送音讯。在效劳端RpcChannel需求挪用CallMethod来挪用Service中的函数。详细完成以下:
class MyRpcChannel(service.RpcChannel):
def __init__(self, rpc_service, conn):
super(MyRpcChannel, self).__init__()
self.logger = LogManager.get_logger("MyRpcChannel")
def CallMethod(self, method_descriptor, rpc_controller, request, response_class, done):
""""protol buffer rpc 需求的函数,用来发送rpc挪用"""
self.logger.info('CallMethod')
cmd_index = method_descriptor.index
assert(cmd_index 65535)
data = request.SerializeToString()
total_len = len(data) + 2
self.conn.send_data(''.join([pack('I', total_len), pack('H', cmd_index), data]))
def from_request(self):
""""从收集剖析出一个完好的恳求以后调的函数"""
index_data = self.rpc_request.data[0:2]
cmd_index = unpack('H', index_data)[0]
rpc_service = self.rpc_service
s_descriptor = rpc_service.GetDescriptor()
method = s_descriptor.methods[cmd_index]
try:
request = rpc_service.GetRequestClass(method)()
serialized = self.rpc_request.data[2:]
request.ParseFromString(serialized)
rpc_service.CallMethod(method, self.controller, request, None)
except:
self.logger.error("Call rpc method failed!")
self.logger.log_last_except()
return True
末了那是担当GameService,并完成connect_server函数了。
class GameService(game_service_pb2.GameService):
def __init__(self):
self.logger = LogManager.get_logger("GameService")
def connect_server(self, rpc_controller, request, callback):
self.logger.info('%s', request.message)
至于用于收集收发音讯的RpcConnector,可使用python的asyncore库完成,详细完成在这就不评论了。
从下面的完成来看,protobuf rpc的完成首要囊括编写proto文件并编译天生对应的service_pb2文件,担当RpcChannel并完成CallMethod和挪用Service的CallMethod,担当Service来完成表露给客户真个函数。
Electron 框架中调用 Python 构建桌面应用
不同的语言、框架都有自己擅长的领域:Electron 基于 Chromium 和 Node.js 能以 Web 开发的模式打造桌面应用,开发用户界面又快捷又简单;Python 则在数据分析、自动化脚本等领域有非常多的应用。两者的社区生态都十分强大,由两者共同构建应用,在界面开发、功能、性能上能够强强联合;
为了简单验证技术可行性,我们来编写一个 Demo:
目的:验证 Electron 打造的桌面应用能够调用 Python,思路是使用 RPC 或 HTTP 或 WebSocket 进行通信
Demo 功能:输入 x、y 坐标,程序会移动鼠标到屏幕的 x,y 位置(通过 python 库 pyautogui 实现)
Demo 运行环境:MacOS、pyInstaller: 版本 4.5.1、python: 版本 3.9.7
源码:-------- 项目源码 --------
注意:移动鼠标需要授予应用控制权限,在 MacOS 下设置 偏好设置 - 隐私 - 辅助功能 - 允许对应的应用。
技术栈:NodeJS、Electron、Python、aiohttp(HTTP、WebSocket)、pyautogui(控制鼠标)
为了使 NodeJS 和 Python 能够通信,Python 需要启动一个本地通信服务,Demo 中 py/api.py 能够启动一个本地 HTTP 服务:
然后我们需要执行 Python 代码以启动服务,为了使 NodeJS 可以执行 Python,我们使用 pyinstaller 将 Python 打包成可执行文件:
Python 启动了本地 HTTP 服务后,Chromium 和 Node.js 就可以通过请求的方式,与 python 连接通信了:
简单来说三个步骤:
本项目只是一个验证思路的 Demo,真的需要在项目上实践,还需要考虑以下几个点:
应该使用 RPC 通信而不是 HTTP 或者 WebSocket,Demo 使用 HTTP 只是搭建方便。实践中在建立连接、保持连接、异常重连都需要编写更多的逻辑来处理。为什么 Demo 没有使用 zerorpc? 这个库已经 4 年没有维护了,不兼容新版 NodeJS。
项目通过 pyinstaller 打包成可执行文件来调用 python。实际上其他能编译为可执行文件的语言也一样。还可以使用 WebAssembly 将其他语言编译成 .wasm,在 NodeJS 中引入执行。
微服务跨语言调用(摘选)
微服务架构已成为目前互联网架构的趋势,关于微服务的讨论,几乎占据了各种技术大会的绝大多数版面。国内使用最多的服务治理框架非阿里开源的 dubbo 莫属,千米网也选择了 dubbo 作为微服务治理框架。另一方面,和大多数互联网公司一样,千米的开发语言是多样的,大多数后端业务由 java 支撑,而每个业务线有各自开发语言的选择权,便出现了 nodejs,python,go 多语言调用的问题。
跨语言调用是一个很大的话题,也是一个很有挑战的技术活,目前业界经常被提及的解决方案有如下几种,不妨拿出来老生常谈一番:
当我们再聊跨语言调用时我们在聊什么?纵观上述几个较为通用,成熟的解决方案,可以得出结论:解决跨语言调用的思路无非是两种:
如果一个新型的团队面临技术选型,我认为上述的方案都可以纳入参考,可考虑到遗留系统的兼容性问题
旧系统的迁移成本
这也关键的选型因素。我们做出的第一个尝试,便是在 RPC 协议上下功夫。
通用协议的跨语言支持
springmvc的美好时代
springmvc
springmvc
在没有实现真正的跨语言调用之前,想要实现“跨语言”大多数方案是使用 http 协议做一层转换,最常见的手段莫过于借助 springmvc 提供的 controller/restController,间接调用 dubbo provider。这种方案的优势和劣势显而易见
通用协议的支持
事实上,大多数服务治理框架都支持多种协议,dubbo 框架除默认的 dubbo 协议之外,还有当当网扩展的 rest协议和千米网扩展的 json-rpc 协议可供选择。这两者都是通用的跨语言协议。
rest 协议为满足 JAX-RS 2.0 标准规范,在开发过程中引入了 @Path,@POST,@GET 等注解,习惯于编写传统 rpc 接口的人可能不太习惯 rest 风格的 rpc 接口。一方面这样会影响开发体验,另一方面,独树一帜的接口风格使得它与其他协议不太兼容,旧接口的共生和迁移都无法实现。如果没有遗留系统,rest 协议无疑是跨语言方案最简易的实现,绝大多数语言支持 rest 协议。
和 rest 协议类似,json-rpc 的实现也是文本序列化http 协议。dubbox 在 restful 接口上已经做出了尝试,但是 rest 架构和 dubbo 原有的 rpc 架构是有区别的,rest 架构需要对资源(Resources)进行定义, 需要用到 http 协议的基本操作 GET、POST、PUT、DELETE。在我们看来,restful 更合适互联网系统之间的调用,而 rpc 更适合一个系统内的调用。使用 json-rpc 协议使得旧接口得以兼顾,开发习惯仍旧保留,同时获得了跨语言的能力。
千米网在早期实践中采用了 json-rpc 作为 dubbo 的跨语言协议实现,并开源了基于 json-rpc 协议下的 python 客户端 dubbo-client-py 和 node 客户端 dubbo-node-client,使用 python 和 nodejs 的小伙伴可以借助于它们直接调用 dubbo-provider-java 提供的 rpc 服务。系统中大多数 java 服务之间的互相调用还是以 dubbo 协议为主,考虑到新旧协议的适配,在不影响原有服务的基础上,我们配置了双协议。
dubbo 协议主要支持 java 间的相互调用,适配老接口;json-rpc 协议主要支持异构语言的调用。
定制协议的跨语言支持
微服务框架所谓的协议(protocol)可以简单理解为:报文格式和序列化方案。服务治理框架一般都提供了众多的协议配置项供使用者选择,除去上述两种通用协议,还存在一些定制化的协议,如 dubbo 框架的默认协议:dubbo 协议以及 motan 框架提供的跨语言协议:motan2。
motan2协议的跨语言支持
motan2
motan2
motan2 协议被设计用来满足跨语言的需求主要体现在两个细节中—MetaData 和 motan-go。在最初的 motan 协议中,协议报文仅由 Header+Body 组成,这样导致 path,param,group 等存储在 Body 中的数据需要反序列得到,这对异构语言来说是很不友好的,所以在 motan2 中修改了协议的组成;weibo 开源了 motan-go ,motan-php ,motan-openresty ,并借助于 motan-go 充当了 agent 这一翻译官的角色,使用 simple 序列化方案来序列化协议报文的 Body 部分(simple 序列化是一种较弱的序列化方案)。
agent
agent
仔细揣摩下可以发现这么做和双协议的配置区别并不是大,只不过这里的 agent 是隐式存在的,与主服务共生。明显的区别在于 agent 方案中异构语言并不直接交互。
dubbo协议的跨语言支持
dubbo 协议设计之初只考虑到了常规的 rpc 调用场景,它并不是为跨语言而设计,但跨语言支持从来不是只有支持、不支持两种选择,而是要按难易程度来划分。是的,dubbo 协议的跨语言调用可能并不好做,但并非无法实现。千米网便实现了这一点,nodejs 构建的前端业务是异构语言的主战场,最终实现了 dubbo2.js,打通了 nodejs 和原生 dubbo 协议。作为本文第二部分的核心内容,重点介绍下我们使用 dubbo2.js 干了什么事。
Dubbo协议报文格式
dubbo协议
dubbo协议
dubbo协议报文消息头详解:
magic:类似java字节码文件里的魔数,用来判断是不是 dubbo 协议的数据包。魔数是常量 0xdabb
flag:标志位, 一共8个地址位。低四位用来表示消息体数据用的序列化工具的类型(默认 hessian),高四位中,第一位为 1 表示是 request 请求,第二位为 1 表示双向传输(即有返回 response),第三位为 1 表示是心跳 ping 事件。
status:状态位, 设置请求响应状态,dubbo 定义了一些响应的类型。具体类型见com.alibaba.dubbo.remoting.exchange.Response
invoke id:消息 id, long 类型。每一个请求的唯一识别 id(由于采用异步通讯的方式,用来把请求 request 和返回的 response 对应上)
body length:消息体 body 长度, int 类型,即记录 Body Content 有多少个字节
body content:请求参数,响应参数的抽象序列化之后存储于此。
协议报文最终都会变成字节,使用 tcp 传输,任何语言只要支持网络模块,有类似 Socket 之类的封装,那么通信就不成问题。那,跨语言难在哪儿?以其他语言调用 java 来说,主要有两个难点:
ps:dubbo 协议通讯demo( )
从 0 到 1:全面理解 RPC 远程调用
作者 | Python编程时光
责编 | 胡巍巍
什么是RPC呢?百度百科给出的解释是这样的:“RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议”。
这个概念听起来还是比较抽象,没关系,继续往后看,后面概念性的东西,我会讲得足够清楚,让你完全掌握 RPC 的基础内容。
在 OpenStack 里的进程间通信方式主要有两种,一种是基于HTTP协议的RESTFul API方式,另一种则是RPC调用。
那么这两种方式在应用场景上有何区别呢?
有使用经验的人,就会知道:
首先,给你提两个问题,带着这两个问题再往下看:
1、RPC 和 REST 区别是什么?2、为什么要采用RPC呢?
首先,第一个问题:RPC 和 REST 区别是什么?
你一定会觉得这个问题很奇怪,是的,包括我,但是你在网络上一搜,会发现类似对比的文章比比皆是,我在想可能很多初学者由于基础不牢固,才会将不相干的二者拿出来对比吧。既然是这样,那为了让你更加了解陌生的RPC,就从你熟悉得不能再熟悉的 REST 入手吧。
01、所属类别不同
REST,是Representational State Transfer 的简写,中文描述表述性状态传递(是指某个瞬间状态的资源数据的快照,包括资源数据的内容、表述格式(XML、JSON)等信息。)
REST 是一种软件架构风格。这种风格的典型应用,就是HTTP。其因为简单、扩展性强的特点而广受开发者的青睐。
而RPC 呢,是 Remote Procedure Call Protocol 的简写,中文描述是远程过程调用,它可以实现客户端像调用本地服务(方法)一样调用服务器的服务(方法)。
而 RPC 可以基于 TCP/UDP,也可以基于 HTTP 协议进行传输的,按理说它和REST不是一个层面意义上的东西,不应该放在一起讨论,但是谁让REST这么流行呢,它是目前最流行的一套互联网应用程序的API设计标准,某种意义下,我们说 REST 可以其实就是指代 HTTP 协议。
02、使用方式不同
03、面向对象不同
从设计上来看,RPC,所谓的远程过程调用 ,是面向方法的 ,REST:所谓的 Representational state transfer ,是面向资源的,除此之外,还有一种叫做 SOA,所谓的面向服务的架构,它是面向消息的,这个接触不多,就不多说了。
04、序列化协议不同
接口调用通常包含两个部分,序列化和通信协议。
通信协议,上面已经提及了,REST 是 基于 HTTP 协议,而 RPC 可以基于 TCP/UDP,也可以基于 HTTP 协议进行传输的。
常见的序列化协议,有:json、xml、hession、protobuf、thrift、text、bytes等,REST 通常使用的是 JSON或者XML,而 RPC 使用的是 JSON-RPC,或者 XML-RPC。
通过以上几点,我们知道了 REST 和 RPC 之间有很明显的差异。
然后第二个问题:为什么要采用RPC呢?
那到底为何要使用 RPC,单纯的依靠RESTful API不可以吗?为什么要搞这么多复杂的协议,渣渣表示真的学不过来了。
关于这一点,以下几点仅是我的个人猜想,仅供交流哈:
说了这么多,我们该如何选择这两者呢?我总结了如下两点,供你参考:
“远程调用”意思就是:被调用方法的具体实现不在程序运行本地,而是在别的某个地方(分布到各个服务器),调用者只想要函数运算的结果,却不需要实现函数的具体细节。
光说不练嘴把式,接下来,我将分别用三种不同的方式全面地让你搞明白 rpc 远程调用是如何实现的。
01、基于 xml-rpc
Python实现 rpc,可以使用标准库里的 SimpleXMLRPCServer,它是基于XML-RPC 协议的。
有了这个模块,开启一个 rpc server,就变得相当简单了。执行以下代码:
有了 rpc server,接下来就是 rpc client,由于我们上面使用的是 XML-RPC,所以 rpc clinet 需要使用xmlrpclib 这个库。
然后,我们通过 server_proxy 对象就可以远程调用之前的rpc server的函数了。
SimpleXMLRPCServer是一个单线程的服务器。这意味着,如果几个客户端同时发出多个请求,其它的请求就必须等待第一个请求完成以后才能继续。
若非要使用 SimpleXMLRPCServer 实现多线程并发,其实也不难。只要将代码改成如下即可。
02、基于json-rpc
SimpleXMLRPCServer 是基于 xml-rpc 实现的远程调用,上面我们也提到 除了 xml-rpc 之外,还有 json-rpc 协议。
那 python 如何实现基于 json-rpc 协议呢?
答案是很多,很多web框架其自身都自己实现了json-rpc,但我们要独立这些框架之外,要寻求一种较为干净的解决方案,我查找到的选择有两种
第一种是 jsonrpclib
第二种是 python-jsonrpc
先来看第一种 jsonrpclib
它与 Python 标准库的 SimpleXMLRPCServer 很类似(因为它的类名就叫做 SimpleJSONRPCServer ,不明真相的人真以为它们是亲兄弟)。或许可以说,jsonrpclib 就是仿照 SimpleXMLRPCServer 标准库来进行编写的。
它的导入与 SimpleXMLRPCServer 略有不同,因为SimpleJSONRPCServer分布在jsonrpclib库中。
服务端
客户端
再来看第二种python-jsonrpc,写起来貌似有些复杂。
服务端
客户端
调用过程如下
还记得上面我提到过的 zabbix API,因为我有接触过,所以也拎出来讲讲。zabbix API 也是基于 json-rpc 2.0协议实现的。
因为内容较多,这里只带大家打个,zabbix 是如何调用的:直接指明要调用 zabbix server 的哪个方法,要传给这个方法的参数有哪些。
03、基于 zerorpc
以上介绍的两种rpc远程调用方式,如果你足够细心,可以发现他们都是http+rpc 两种协议结合实现的。
接下来,我们要介绍的这种(zerorpc),就不再使用走 http 了。
zerorpc 这个第三方库,它是基于TCP协议、 ZeroMQ 和 MessagePack的,速度相对快,响应时间短,并发高。zerorpc 和 pyjsonrpc 一样,需要额外安装,虽然SimpleXMLRPCServer不需要额外安装,但是SimpleXMLRPCServer性能相对差一些。
调用过程如下
客户端除了可以使用zerorpc框架实现代码调用之外,它还支持使用“命令行”的方式调用。
客户端可以使用命令行,那服务端是不是也可以呢?
是的,通过 Github 上的文档几个 demo 可以体验到这个第三方库做真的是优秀。
比如我们可以用下面这个命令,创建一个rpc server,后面这个 time Python 标准库中的 time 模块,zerorpc 会将 time 注册绑定以供client调用。
经过了上面的学习,我们已经学会了如何使用多种方式实现rpc远程调用。
通过对比,zerorpc 可以说是脱颖而出,一支独秀。
为此,我也做了一番思考:
OpenStack 组件繁多,在一个较大的集群内部每个组件内部通过rpc通信频繁,如果都采用rpc直连调用的方式,连接数会非常地多,开销大,若有些 server 是单线程的模式,超时会非常的严重。
OpenStack 是复杂的分布式集群架构,会有多个 rpc server 同时工作,假设有 server01,server02,server03 三个server,当 rpc client 要发出rpc请求时,发给哪个好呢?这是问题一。
你可能会说轮循或者随机,这样对大家都公平。这样的话还会引出另一个问题,倘若请求刚好发到server01,而server01刚好不凑巧,可能由于机器或者其他因为导致服务没在工作,那这个rpc消息可就直接失败了呀。要知道做为一个集群,高可用是基本要求,如果出现刚刚那样的情况其实是很尴尬的。这是问题二。
集群有可能根据实际需要扩充节点数量,如果使用直接调用,耦合度太高,不利于部署和生产。这是问题三。
引入消息中间件,可以很好的解决这些问题。
解决问题一:消息只有一份,接收者由AMQP的负载算法决定,默认为在所有Receiver中均匀发送(round robin)。
解决问题二:有了消息中间件做缓冲站,client 可以任性随意的发,server 都挂掉了?没有关系,等 server 正常工作后,自己来消息中间件取就行了。
解决问题三:无论有多少节点,它们只要认识消息中间件这一个中介就足够了。
既然讲到了消息队列,如果你之前没有接触过这块内容,最好花几分钟的时间跟我好好过下关于消息队列的几个基础概念。
首先,RPC只是定义了一个通信接口,其底层的实现可以各不相同,可以是 socket,也可以是今天要讲的 AMQP。
AMQP(Advanced Message Queuing Protocol)是一种基于队列的可靠消息服务协议,作为一种通信协议,AMQP同样存在多个实现,如Apache Qpid,RabbitMQ等。
以下是 AMQP 中的几个必知的概念:
Publisher:消息发布者
Queue:用来保存消息的存储空间,消息没有被receiver前,保存在队列中。
Exchange:用来接收Publisher发出的消息,根据Routing key 转发消息到对应的Message Queue中,至于转到哪个队列里,这个路由算法又由exchange type决定的。
Exchange type:主要四种描述exchange的类型。
direct:消息路由到满足此条件的队列中(queue,可以有多个):routing key = binding key
topic:消息路由到满足此条件的队列中(queue,可以有多个):routing key 匹配 binding pattern. binding pattern是类似正则表达式的字符串,可以满足复杂的路由条件。
fanout:消息路由到多有绑定到该exchange的队列中。
binding :binding是用来描述exchange和queue之间的关系的概念,一个exchang可以绑定多个队列,这些关系由binding建立。前面说的binding key /binding pattern也是在binding中给出。
为了让你明白这几者的关系,我画了一张模型图。
关于AMQP,有几下几点值得注意:
前面铺垫了那么久,终于到了讲真实应用的场景。在生产中RPC是如何应用的呢?
其他模型我不太清楚,在 OpenStack 中的应用模型是这样的
至于为什么要如此设计,前面我已经给出了自己的观点。
接下来,就是源码解读 OpenStack ,看看其是如何通过rpc进行远程调用的。如若你对此没有兴趣(我知道很多人对此都没有兴趣,所以不浪费大家时间),可以直接跳过这一节,进入下一节。
目前Openstack中有两种RPC实现,一种是在oslo messaging,一种是在openstack.common.rpc。
openstack.common.rpc是旧的实现,oslo messaging是对openstack.common.rpc的重构。openstack.common.rpc在每个项目中都存在一份拷贝,oslo messaging即将这些公共代码抽取出来,形成一个新的项目。oslo messaging也对RPC API 进行了重新设计,对多种 transport 做了进一步封装,底层也是用到了kombu这个AMQP库。(注:Kombu 是Python中的messaging库。Kombu旨在通过为AMQ协议提供惯用的高级接口,使Python中的消息传递尽可能简单,并为常见的消息传递问题提供经过验证和测试的解决方案。)
关于oslo_messaging库,主要提供了两种独立的API:
因为 notify 实现是太简单了,所以这里我就不多说了,如果有人想要看这方面内容,可以收藏我的博客() ,我会更新补充 notify 的内容。
OpenStack RPC 模块提供了 rpc.call,rpc.cast, rpc.fanout_cast 三种 RPC 调用方法,发送和接收 RPC 请求。
rpc.call 和 .rpc.cast 从实现代码上看,他们的区别很小,就是call调用时候会带有wait_for_reply=True参数,而cast不带。
要了解 rpc 的调用机制呢,首先要知道 oslo_messaging 的几个概念主要方法有四个:
transport:RPC功能的底层实现方法,这里是rabbitmq的消息队列的访问路径
transport 就是定义你如何访连接消息中间件,比如你使用的是 Rabbitmq,那在 nova.conf中应该有一行transport_url的配置,可以很清楚地看出指定了 rabbitmq 为消息中间件,并配置了连接rabbitmq的user,passwd,主机,端口。
target用来表述 RPC 服务器监听topic,server名称和server监听的exchange,是否广播fanout。
rpc server 要获取消息,需要定义target,就像一个门牌号一样。
rpc client 要发送消息,也需要有target,说明消息要发到哪去。
endpoints:是可供别人远程调用的对象
RPC服务器暴露出endpoint,每个 endpoint 包涵一系列的可被远程客户端通过 transport 调用的方法。直观理解,可以参考nova-conductor创建rpc server的代码,这边的endpoints就是 nova/manager.py:ConductorManager
dispatcher:分发器,这是 rpc server 才有的概念
只有通过它 server 端才知道接收到的rpc请求,要交给谁处理,怎么处理?
在client端,是这样指定要调用哪个方法的。
而在server端,是如何知道要执行这个方法的呢?这就是dispatcher 要干的事,它从 endpoint 里找到这个方法,然后执行,最后返回。
Serializer:在 python 对象和message(notification) 之间数据做序列化或是反序列化的基类。
主要方法有四个:
每个notification listener都和一个executor绑定,来控制收到的notification如何分配。默认情况下,使用的是blocking executor(具体特性参加executor一节)
模仿是一种很高效的学习方法,我这里根据 OpenStack 的调用方式,抽取出核心内容,写成一个简单的 demo,有对 OpenStack 感兴趣的可以了解一下,大部分人也可以直接跳过这章节。
注意以下代码不能直接运行,你还需要配置 rabbitmq 的连接方式,你可以写在配置文件中,通过 get_transport 从cfg.CONF 中读取,也可以直接将其写成url的格式做成参数,传给 get_transport 。而且还要nova或者其他openstack组件的环境中运行(因为需要有ctxt这个环境变量)
简单的 rpc client
简单的 rpc server
【End】
热 文 推 荐
☞Facebook 发币 Libra;谷歌十亿美金为穷人造房;第四代树莓派 Raspberry Pi 4 发布 | 开发者周刊
☞WebRTC 将一统实时音视频天下?
☞小米崔宝秋:小米 AIoT 深度拥抱开源
☞华为在美研发机构 Futurewei 意欲分家?
☞老司机教你如何写出没人敢维护的代码!
☞Python有哪些技术上的优点?比其他语言好在哪儿?
☞上不了北大“图灵”、清华“姚班”,AI专业还能去哪上?
☞公链史记 | 从鸿蒙初辟到万物生长的十年激荡……
☞边缘计算容器化是否有必要?
☞马云曾经偶像,终于把阿里留下的1400亿败光了!
你点的每个“在看”,我都认真当成了喜欢