grpc 浅析

gRPC是一个高性能、通用的开源RPC框架,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers)序列化协议开发,且支持众多开发语言。gRPC提供了一种简单的方法来精确地定义服务和为iOS、Android和后台支持服务自动生成可靠性很强的客户端功能库。客户端充分利用高级流和链接功能,从而有助于节省带宽、降低的TCP链接次数、节省CPU使用、和电池寿命。

服务运行流程
proto Request请求 grpcServer < ----------------------------------------grpcStub(可以是各种语言Python,ruby,) -------------------------------------------------> proto Response响应

grpc使用协议缓冲区proto,而不是XML
什么是协议缓冲区?
协议缓冲区是一种灵活,高效,自动化的机制,用于序列化结构化数据 - 想想XML,但更小,更快,更简单。您可以定义数据的结构化结构, 然后使用特殊生成的源代码轻松地将结构化数据写入和读取各种数据流,并使用各种语言。您甚至可以更新数据结构, 而不会破坏根据“旧”格式编译的已部署程序。

协议缓存区工作
通过在.proto文件中定义协议缓冲区消息类型来指定您希望如何构建序列化信息。每个协议缓冲区消息都是一个小的逻辑信息记录, 包含一系列名称 - 值对。以下.proto是定义包含有关人员信息的消息的文件的一个非常基本的示例:

message Person { required string name = 1; required int32 id = 2; optional string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; }message PhoneNumber { required string number = 1; optional PhoneType type = 2 [default = HOME]; }repeated PhoneNumber phone = 4; }

消息格式很简单 - 每种消息类型都有一个或多个唯一编号的字段,每个字段都有一个名称和一个值类型,其中值类型可以是数字(整数或浮点数),布尔值,字符串,原始字节,甚至(如上例所示)其他协议缓冲区消息类型,允许您分层次地构建数据
使用Protocol Buffers的跨平台RPC系统 安装
使用 pip
pip install grpcio pip install grpcio-tools

gRPC由两个部分构成,grpcio 和 gRPC 工具, 后者是编译 protocol buffer 以及提供生成代码的插件。
使用
编写protocol buffer
使用 gRPC 首先需要做的是设计 protocol buffer。新建一个 msg.proto 文件。
// proto 格式文本编译protocol buffer// 首先定义语法版本, 最好使用proto3 更成熟 syntax = 'proto3'; // 使用service 关键字定义服务service Msg{ // get msg rpc GetMsg(Request) returns (Response){}// Sets with str rpc SetString(Request) returns (Response) {} }// 定义 消息数据结构 message Request{ string name=1; }message Response{ string msg=1;

}
以上面的这个消息服务为例,首先是规定语法,这里使用的是 proto3 的语法。接着使用 service 关键字定义服务,gRPC 提供4种 RPC 类型的服务,这里定义的是第一种单一请求单一回应,类似普通的函数调用,其他的使用到了 stream 关键字,将其放在括号里,代表这个数据是流数据。这个以后再来研究,本次先设计一个简单的RPC。
之后定义两个 message ,一个是请求的结构,一个是回应的结果。 这里表示这个数据结构是字符串,protocol buffer 还可以定义为 int32,int64,double,float 等等。这里赋予的初值可以随便填写,实际使用中,会被赋予新的值。
生成接口代码
因为之前安装好了一些辅助插件,使用这里直接可以生成。
python -m grpc_tools.protoc -I . --python_out=. --grpc_python_out=. msg.proto

这里会生成两个文件, msg_pb2.py 和 msg_pb2_grpc.py 。这两个文件是为后续的服务端和客户端所用。前者是定义了一些变量,例如 _MSGREQUEST 中就包含了请求函数的名字,可接受的变量,实际上还是 msg.proto 里定义的东西。
创建服务端
首先需要导入 RPC 必备的包,以及刚才生成的两个文件。
import grpc import msg_pb2 import msg_pb2_grpc

因为 RPC 应该长时间运行,考虑到性能,还需要用到并发的库。
from concurrent import futures import time

完整 msg_server.py 代码如下
import timeimport random import string_day = 60 * 60 * 24class RandStr: _mapping = string.digits + string.ascii_lettersdef rand_str(self, width=16): """ 生成一个指定长度的随机字符串 width: 生成字符串长度 """ return "".join(map(lambda _: random.choice(self._mapping), range(width)))class Msg(msg_pb2_grpc.MsgServicer):def GetMsg(self, request,context): print("接受到的名字是: %s" % request.name) return msg_pb2.Response(msg='欢迎, %s!' % request.name)def SetString(self,request,context): print('%s将要使用仙术变化随机字符串' % request.name) return msg_pb2.Response(msg='%s获得随机字符串,%s!!'%(request.name,RandStr().rand_str(18)))def serve(): server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) msg_pb2_grpc.add_MsgServicer_to_server(Msg(), server) server.add_insecure_port('[::]:8888') server.start() try: while True: time.sleep(_day) except KeyboardInterrupt: server.stop(0)if __name__ == '__main__': serve()

创建客户端
import grpcimport msg_pb2 import msg_pb2_grpcdef run():with grpc.insecure_channel('localhost:8888') as channel: stub = msg_pb2_grpc.MsgStub(channel) response = stub.GetMsg(msg_pb2.Request(name='陛下')) print("客户端接收信息: " + response.msg) res = stub.SetString(msg_pb2.Request(name='神仙')) print("客户端显示信息: " + res.msg)if __name__ == '__main__': run()

使用 grpc.insecure_channel(‘localhost:8888’) 进行连接 服务端, 接着在这个 channel 上创建 stub ,
在 msg_pb2_grpc 里可以找到 MsgServiceStub 这个类相关信息。
这个 stub 可以调用远程的 GetMsg 函数。
Request 中的 name 即 msg.proto 中定义的数据。在回应里可以得到 msg.proto 中定义的 msg 。
【grpc 浅析】运行
首先运行 python msg_server.py 启动服务端,接着运行 python msg_client.py 机会看到客户端接收到了服务端传来的消息

    推荐阅读