来源:https://juejin.im/post/6854573212018147336
序言什么是RPC做事 RPC,是Remote Procedure Call的简称,翻译成中文便是远程过程调用。RPC便是许可程序调用另一个地址空间(常日是另一台机器上)的类方法或函数的一种做事。 它是一种架设在打算机网络之上并隐蔽底层网络技能,可以像调用本地做事一样调用远端程序,在编码代价不高的情形下提升吞吐的能力。
为什么要利用RPC做事 随着打算机技能的快速发展,单台机器运行做事的方案已经不敷以支撑越来越多的网络要求负载,分布式方案开始兴起,一个业务场景可以被拆分在多个机器上运行,每个机器分别只完成一个或几个的业务模块。为了能让其他机器利用某台机器中的业务模块方法,就有了RPC做事,它是基于一种专门实现远程方法调用的协议上完成的做事。现如今很多主流措辞都支持RPC做事,常用的有Java的Dubbo、Go的net/rpc & RPCX、谷歌的gRPC等。

关于gRPC 大部分RPC都是基于socket实现的,可以比http要求来的高效。gRPC是谷歌开拓并开源的一款实现RPC做事的高性能框架,它是基于http2.0协议的,目前已经支持C、C++、Java、Node.js、Python、Ruby、Objective-C、PHP和C#等等措辞。要将方法调用以及调用参数,相应参数等在两个做事器之间进行传输,就须要将这些参数序列化,gRPC采取的是protocol buffer的语法(检讨proto),通过proto语法可以定义好要调用的方法、和参数以及相应格式,可以很方便地完发展途方法调用,而且非常利于扩展和更新参数。
快速上手gRPC
利用gRPC实现远程方法调用之前,我们须要理解protocol buffer语法,安装支持protocol buffer语法编译成.proto文件的工具,然后再完成gRPC的做事端(远程方法供应者)和客户端(调用者)的搭建和封装。
理解protocol bufferProtocol Buffer是Google的跨措辞,跨平台,可扩展机制的,用于序列化构造化数据 - 比拟XML,但更小,更快,更大略的一种数据格式。您可以定义数据的构造化,例如方法的名字、参数和相应格式等,然后可以利用对应的措辞工具天生的源代码轻松地在各种数据流中利用各种措辞编写和读取构造化数据。
语法利用定义类型 package test; syntax = "proto3"; message SearchRequest { string query = 1; int32 page_number = 2; int32 result_per_page = 3; } 复制代码
上面的例子便是一个.proto文件,该文件的第一行指定包名,方便您在别的proto文件中import这个文件的定义,第二行是您正在利用proto3语法:如果您不这样做,protobuf 编译器将假定您正在利用proto2。这必须是文件的第一个非空的非注释行,目前建议利用proto3语法。 SearchRequest是体的名字,指定了三个字段,分别指定了字段的类型和顺序,顺序必须从1开始,并且不可重复;
指定字段规则 字段可以是以下之一:单数(默认):格式良好的可以包含该字段中的零个或一个(但不超过一个)。 repeated:此字段可以在格式良好的中重复任意次数(包括零)。将保留重复值的顺序。例如:
syntax = "proto3"; message SearchRequest { string query = 1; int32 page_number = 2; int32 result_per_page = 3; repeated Body body = 4; } message Body { int32 id = 1; string number = 2; } 复制代码
上述例子实在便是定义了一个格式,用我们常日的json格式表示便是:
{ "query": str, "page_number":int, "result_per_page":int, "body":[ { "id":int, "number":str } ], } 复制代码
标量值类型 标量字段可以具有以下类型之一 - 该表显示.proto文件中指定的类型,以及自动天生的类中的相应类型:
.proto Type备注Python Typdoublefloatfloatfloatint32利用变长编码,对付负值的效率很低,如果你的域有可能有负值,请利用sint64替代intuint32利用变长编码int/longuint64利用变长编码int/longsint32利用变长编码,这些编码在负值时比int32高效的多intsint64利用变长编码,有符号的整型值。编码时比常日的int64高效。int/longfixed32总是4个字节,如果数值总是比总是比228大的话,这个类型会比uint32高效。intfixed64总是8个字节,如果数值总是比总是比256大的话,这个类型会比uint64高效。int/longsfixed32总是4个字节intsfixed64总是8个字节int/longbool布尔值boolstring一个字符串必须是UTF-8编码或者7-bit ASCII编码的文本。str/unicodebytes可能包含任意顺序的字节数据。str
默认值 解析时,如果编码不包含特定的单数元素,则解析工具中的相应字段将设置为该字段的默认值。这些默认值是特定于类型的:对付字符串,默认值为空字符串。对付字节,默认值为空字节。对付bools,默认值为false。对付数字类型,默认值为零。对付列举,默认值是第一个定义的列举值,该值必须为0。重复字段的默认值为空(常日是相应措辞的空列表)列举类型 message SearchRequest { string query = 1; int32 page_number = 2; int32 result_per_page = 3; enum Corpus { UNIVERSAL = 0; WEB = 1; IMAGES = 2; LOCAL = 3; NEWS = 4; PRODUCTS = 5; VIDEO = 6; } Corpus corpus = 4; } 复制代码
Corpus列举的第一个常量映射为零:每个列举定义必须包含一个映射到零的常量作为其第一个元素。这是由于:
必须有一个零值,以便我们可以利用0作为数字默认值。零值必须是第一个元素,以便与proto2语义兼容,个中第一个列举值始终是默认值。定义方法 service SearchService { rpc Search(SearchRequest)returns(SearchResponse); } 复制代码
上面的语句就定义好了远程调用的方法名Search,待编译好对应措辞的源代码之后就可以利用远程调用,例如在Python中初始化SearchService方法,则实行Search方法,便是采取SearchRequest的格式去调用远程机器的方法,然后按定义好的SearchResponse格式返回调用结果。根据proto的语法定义,乃至可以实现跨平台,跨措辞利用这种远程调用。
利用工具天生对应措辞的源代码
根据实际事情须要,天生以下对应措辞的自定义类型Java,Python,C ++,Go, Ruby, Objective-C,或C#的.proto文件,你须要运行protobuf 编译器protoc上.proto。如果尚未安装编译器,请下载该软件包并按照自述文件中的解释进行操作。 Protobuf 编译器的调用如下:
protoc --proto_path = IMPORT_PATH --cpp_out = DST_DIR --java_out = DST_DIR --python_out = DST_DIR --go_out = DST_DIR --ruby_out = DST_DIR --objc_out = DST_DIR --csharp_out = DST_DIR path / to / file .proto 复制代码
Python天生对应的源代码
安装Python的gRPC源码包grpcio,用于实行gRPC的各种底层协议和要求相应方法安装Python基于gRPC的proto天生python源代码的工具grpcio-tools sudo python -m pip install grpcio python -m pip install grpcio-tools 复制代码
实行编译天生python的proto序列化协议源代码:
# 编译 proto 文件 python -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I. test.proto python -m grpc_tools.protoc: python 下的 protoc 编译器通过 python 模块(module) 实现, 以是说这一步非常省心 --python_out=. : 编译天生处理 protobuf 干系的代码的路径, 这里天生到当前目录 --grpc_python_out=. : 编译天生处理 grpc 干系的代码的路径, 这里天生到当前目录 -I. test.proto : proto 文件的路径, 这里的 proto 文件在当前目录 复制代码
编译后天生的源代码:
test_pb2.py: 用来和 protobuf 数据进行交互,这个便是根据proto文件定义好的数据构造类型天生的python化的数据构造文件test_pb2_grpc.py: 用来和 grpc 进行交互,这个便是定义了rpc方法的类,包含了类的要求参数和相应等等,可用python直接实例化调用搭建Python gRPC做事天生好了python可以直接实例化和调用的gRPC类,我们就可以开始搭建RPC的做事端(远程调用供应者)和客户端(调用者)了。
搭建做事端server.py from concurrent import futures import time import grpc import test_pb2 import test_pb2_grpc # 实现 proto 文件中定义的 SearchService class RequestRpc(test_pb2_grpc.SearchService): # 实现 proto 文件中定义的 rpc 调用 def doRequest(self, request, context): return test_pb2.Search(query = 'hello {msg}'.format(msg = request.name)) # return的数据是符合定义的SearchResponse格式 def serve(): # 启动 rpc 做事,这里可定义最大吸收和发送大小(单位M),默认只有4M server = grpc.server(futures.ThreadPoolExecutor(max_workers=10), options=[ ('grpc.max_send_message_length', 100 1024 1024), ('grpc.max_receive_message_length', 100 1024 1024)]) test_pb2_grpc.add_SearchServiceServicer_to_server(RequestRpc(), server) server.add_insecure_port('[::]:50051') server.start() try: while True: time.sleep(606024) # one day in seconds except KeyboardInterrupt: server.stop(0) if __name__ == '__main__': serve() 复制代码
搭建客户端client.py
import grpc import helloworld_pb2 import helloworld_pb2_grpc def run(): # 连接 rpc 做事器 channel = grpc.insecure_channel('localhost:50051') # 调用 rpc 做事 stub = test_pb2_grpc.SearchServiceStub(channel) response = stub.doRequest(test_pb2.SearchRequest(query='henry')) print("client received: ", response) if __name__ == '__main__': run() 复制代码
最佳实践编写proto文件的时候,把稳定义好数据的格式,要多考虑可扩展性,例如可以定义api_version等用于区分版本,防止未来的版本有大的数据格式更新的时候可以兼容;对付不可变类型,建议利用列举,例如要求一个字段type,取值是固定的时候,可以用列举类型;对付做事端和客户真个编写,建议指定好最大吸收和发送大小,避免涌现数据溢出的非常;gRPC偶尔会涌现断线重连的情形,以是要增加非常处理机制,捕获到由于重连时引发远程调用失落败的问题,则可以实行重试(会在接下来的文章中详细解释);gRPC可以采取SSL或TLS的协议,实现http2.0加密传输,提高系统的安全性(会在接下来的文章中详细解释);对付流量、并发较大的做事,可以通过微做事的一些运用或组件(如istio)等实现流量的熔断、限流等等,提高稳定性。gRPC的上风性能
gRPC利用一种有效的二进制格式protobuf进行序列化。Protobuf在做事器和客户机上的序列化非常快。Protobuf序列化后的体积很小,能够有效负载,在移动运用程序等有限带宽场景中显得很主要。
gRPC是为HTTP/2而设计的,它是HTTP的一个紧张版本,与HTTP 1.x比较具有显著的性能上风:
二进制框架和压缩。HTTP/2协议在发送和吸收方面都很紧凑和高效。通过单个TCP连接复用多个HTTP/2调用。多路复用肃清了线头壅塞。代码天生所有gRPC框架都为代码天生供应了一流的支持。gRPC开拓的核心文件是.proto文件 ,它定义了gRPC做事和的约定。根据这个文件,gRPC框架将天生做事基类,和完全的客户端代码。
通过在做事器和客户端之间共享.proto文件,可以从端到端天生和客户端代码。客户真个代码天生肃清了客户端和做事器上的重复,并为您创建了一个强类型的客户端。无需编写客户端代码,可在具有许多做事的运用程序中节省大量开拓韶光。
严格的规范不存在具有JSON的HTTP API的正式规范。开拓职员不须要谈论URL,HTTP动词和相应代码的最佳格式。(想想,是用Post还是Get好?利用Get还是用Put好?一想到有选择恐怖症的你是不是又开了纠结,然后摧残浪费蹂躏了大量的韶光)
该gRPC规范是规定有关gRPC做事必须遵照的格式。gRPC肃清了辩论并节省了开拓职员的韶光,由于gPRC在各个平台和实现之间是同等的。
流HTTP/2为长期的实时通信流供应了根本。gRPC通过HTTP/2为流媒体供应一流的支持。
gRPC做事支持所有流组合:
一元(没有流媒体)做事器到客户端流客户端到做事器流双向流媒体 截至韶光/超时和取消 gRPC许可客户端指定他们乐意等待RPC完成的韶光。该期限被发送到做事端,做事端可以决定在超出了限期时采纳什么行动。例如,做事器可能会在超时时取消正在进行的gRPC / HTTP /数据库要求。通过子gRPC调用截至韶光和取消操作有助于履行资源利用限定。
推举利用gRPC的场景微做事 - gRPC设计为低延迟和高吞吐量通信。gRPC非常适用于效率至关主要的轻型微做事。 点对点实时通信 - gRPC对双向流媒体供应出色的支持。gRPC做事可以实时推送而无需轮询。 多措辞稠浊开拓环境 - gRPC工具支持所有盛行的开拓措辞,使gRPC成为多措辞开拓环境的空想选择。网络受限环境 - 利用Protobuf(一种轻量级格式)序列化gRPC。gRPC始终小于等效的JSON。参考文献https://juejin.im/post/6844903687089831944https://doc.oschina.net/grpc?t=58008https://juejin.im/post/6844903794350751757https://www.jianshu.com/p/43fdfeb105ff