1. 什么是gRPC
grpc 是由谷歌推出的一个高性能、开源、通用的rpc框架, 它基于http/2标准协议, 采用protobuf(Protocol Buffers)作为数据传输格式, 提供了多种语言的支持。
grpc的两个核心组件:
protobuf: 谷歌的高性能、可扩展、结构化数据存储格式,支持多种语言
http/2: 具有流控制、多路复用等功能的tcp基础协议
与RESTful API比较, grpc 的优势:
它支持流数据,可在多个消息之间建立一条TCP连接, 每个消息只是流中的一个包
每个包就是一个RPC,因此它允许服务器同时向客户端推送多个消息/对象
gRPC 的协议使用的是二进制,不像 JSON 和 XML 那样文本格式在更新和升级时产生大量的额外字节
使用ProtoBufs 进行序列化(而不是JSON),因此它不仅更小,而且速度更快
2. gRPC服务的搭建
2.1 安装grpc
利用pip命令安装grpc:
pip install grpcio
安装完grpcio后安装grpcio-tools:
pip install grpcio-tools
2.2 定义proto文件
在proto文件中定义服务和数据类型:
syntax = "proto3";
// 定义 Hello Service
service Greeter {
// 定义 SayHello 方法
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
2.3 生成代码
执行命令生成python文件:
python -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I. hello.proto
将会在当前目录下生成hello_pb2.py和hello_pb2_grpc.py两个文件, pb2.py文件中包含生成的消息的定义, pb2_grpc.py文件中包含生成的 RPC 服务接口和方法。
2.4 实现服务
在hello_pb2_grpc.py文件中找到GreeterServicer类, 并在其中实现服务:
class GreeterServicer(hello_pb2_grpc.GreeterServicer):
def SayHello(self, request, context):
return hello_pb2.HelloReply(message=f"Hello, {request.name}!")
其中SayHello方法即为在proto文件中定义的方法
2.5 创建服务器
在服务器文件中创建服务器, 并设置绑定端口, 配置线程池:
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
hello_pb2_grpc.add_GreeterServicer_to_server(GreeterServicer(), server)
server.add_insecure_port('[::]:50051')
server.start()
server.wait_for_termination()
10个线程的线程池是使用futures库创建的ThreadPoolExecutor对象, 在add_GreeterServicer_to_server()方法中将GreeterServicer类对象和服务器对象进行绑定, 在add_insecure_port()方法中设置绑定端口, 在start()函数中启动服务器
3. 客户端的访问
通过在客户端实例化一个实现方法的stub, 可以通过网络请求到服务端数据。看下面的示例:
def run():
channel = grpc.insecure_channel('localhost:50051')
stub = hello_pb2_grpc.GreeterStub(channel)
response = stub.SayHello(hello_pb2.HelloRequest(name="grpc"))
print("Greeter client received: " + response.message)
在创建的客户端通道中指定服务器的地址和绑定的端口。然后实例化GreeterStub类以及其中的SayHello方法,并通过实例传递HelloRequest对象请求到服务端,并打印服务端返回的HelloReply对象中的message
4. 运行gRPC服务
运行服务器文件即可启动gRPC服务:
if __name__ == '__main__':
serve()
然后在客户端文件中运行客户端即可执行RPC调用:
if __name__ == '__main__':
run()
至此,一个最简单的gRPC服务就搭建完成了!