1.啥是RPC?
远程过程调用(英语:Remote Procedure Call,缩写为 RPC,也叫远程程序调用)是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。如果涉及的软件采用面向对象编程,那么远程过程调用亦可称作远程调用或远程方法调用。
广义
我们可以将所有通过网络来进行通讯调用的实现统称为RPC。
按照这样来理解的话,那我们发现HTTP其实也算是一种RPC实现。
狭义
区别于HTTP的实现方式,在传输的数据格式上和传输的控制上独立实现。比如在机器间通讯传输的数据不采用HTTP协议的方式(分为起始行、header、body三部份),而是使用自定义格式的二进制方式。
RPC VS http优缺点:
优点
-
效率高
-
发起RPC调用的一方,在编写代码时可忽略RPC的具体实现,如同编写本地函数调用一样
缺点 -
通用性不如HTTP好
因为传输的数据不是HTTP协议格式,所以调用双方需要专门实现的通信库,对于不同的编程开发语言,都要有相关实现。而HTTP作为一个标准协议,大部分的语言都已有相关的实现,通用性更好。 -
HTTP更多的面向用户与产品服务器的通讯。
-
RPC更多的面向产品内部服务器间的通讯。
RPC结构
RPC的设计思想是力图使远程调用中的通讯细节对于使用者透明,调用双方无需关心网络通讯的具体实现。因而实现RPC要进行一定的封装。
流程:
调用者(Caller, 也叫客户端、Client)以本地调用的方式发起调用;
Client stub(客户端存根,可理解为辅助助手)收到调用后,负责将被调用的方法名、参数等打包编码成特定格式的能进行网络传输的消息体;
Client stub将消息体通过网络发送给对端(服务端)
Server stub(服务端存根,同样可理解为辅助助手)收到通过网络接收到消息后按照相应格式进行拆包解码,获取方法名和参数;
Server stub根据方法名和参数进行本地调用;
被调用者(Callee,也叫Server)本地调用执行后将结果返回给server stub;
Server stub将返回值打包编码成消息,并通过网络发送给对端(客户端);
Client stub收到消息后,进行拆包解码,返回给Client;
Client得到本次RPC调用的最终结果。
gRPC
gRPC是由Google公司开源的高性能RPC框架。gRPC支持多语言,gRPC原生使用C、Java、Go进行了三种实现,而C语言实现的版本进行封装后又支持C++、C#、Node、ObjC、 Python、Ruby、PHP等开发语言,支持多平台,gRPC的消息协议使用Google自家开源的Protocol Buffers协议机制(proto3) 序列化,gRPC的传输使用HTTP/2标准,支持双向流和连接多路复用
使用方法:
使用Protocol Buffers(proto3)的IDL接口定义语言定义接口服务,编写在文本文件(以.proto为后缀名)中。
使用protobuf编译器生成服务器和客户端使用的stub代码
编写补充服务器和客户端逻辑代码
gRPC中推荐使用proto3版本
使用:
Protocol Buffers文档的第一行非注释行,为版本申明,不填写的话默认为版本2。
syntax = "proto3";
或者
syntax = "proto2";
Package包
Protocol Buffers 可以声明package,来防止命名冲突。 Packages是可选的。
package foo.bar;
message Open { ... }
导包:
Protocol Buffers 中可以导入其它文件消息等,与Python的import类似。
import “myproject/other_protos.proto”;
注释:
// 单行住址
/* */ 多行注释
代码生成
安装protobuf编译器和grpc库
pip install grpcio-tools
编写.proto文件
…
编译生成代码
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. reco.proto
参数说明:
- -I表示搜索proto文件中被导入文件的目录
- –python_out表示保存生成Python文件的目录,生成的文件中包含接口定义中的数据类型
- –grpc_python_out表示保存生成Python文件的目录,生成的文件中包含接口定义中的服务类型
服务端、客户端
Server
def serve():
"""
rpc服务端启动方法
"""
# 创建一个rpc服务器
server = grpc.server(ThreadPoolExecutor(max_workers=10))
# 向服务器中添加被调用的服务方法
# 此处调用函数
# 微服务器绑定ip地址和端口
server.add_insecure_port('127.0.0.1:8888')
# 启动rpc服务
server.start()
# start()不会阻塞,此处需要加上循环睡眠 防止程序退出
while True:
time.sleep(10)
client
def run():
"""
rpc客户端调用的方法
"""
# 使用with语句连接rpc服务器
with grpc.insecure_channel('127.0.0.1:8888') as channel:
# 创建调用rpc远端服务的辅助对象stub
# 通过stub进行rpc调用