gRPC(google RPC)使用 Protocol Buffers
作为它的接口定义语言(Interface Definition Language,IDL)以及它的底层消息交换格式。通过 gRPC,client 应用程序可以直接调用位于不同机器上的 server 应用程序的接口,就好像 client 应用程序和 server 应用程序在同一个进程中一样。这篇文章介绍如何在 Python 中使用 gRPC。
gRPC 的核心思想是:定义一个 service,并指定该 service 所提供的方法以及方法的请求参数/返回结果的类型。在 server 端,需要实现这些接口,并启动一个 gRPC server
来处理客户端请求,在客户端,通过 stub
来调用这些方法。
Protocol Buffers
是 gRPC 的底层消息交换格式,gRPC 使用 protobuf 来进行结构数据的序列化/反序列化。同时 Protocol Buffers
也是 gRPC 的 IDL,gRPC 允许你定义四种类型的服务方法:
- Unary RPCs:client 发送单个请求,server 返回一个响应。就和普通的函数调用类似
例如:
1 | rpc SayHello(HelloRequest) returns (HelloResponse); |
- Server streaming RPCs:client 发送单个请求,server 可以返回响应消息流
例如:
1 | rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse); |
- Client streaming RPCs:client 发送请求消息流,server 返回单个响应
例如:
1 | rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse); |
- Bidirectional streaming RPCs:client 可以发送请求消息流、server 可以返回应答消息流
例如:
1 | rpc BidiHello(stream HelloRequest) returns (stream HelloResponse); |
接下来将介绍如何在 Python 中使用 gRPC。
安装 gRPC
首先创建一个测试虚拟环境:
1 | $ virtualenv grpc-env |
安装 gRPC:
1 | pip install grpcio |
Python 的 gRPC 工具包含 protocol buffer
编译器 protoc
以及一个能够根据 proto
文件生成 server 和 client 代码的特殊插件。使用如下命令安装 gRPC 工具包:
1 | pip install grpcio-tools |
Hello World
接下来使用 Python gRPC 包生成一个服务器和客户端程序。gRPC 通过 .proto
文件来定义服务接口和消息类型,因此首先需要编写一个 proto
文件:
1 | syntax = "proto3"; |
接下来执行如下命令根据该 proto 文件生成对应 python gRPC 代码,我们的程序会使用这些生成的 gRPC 代码来进行通信:
1 | python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. hello_world.proto |
- -I 选项:指定搜索 proto 文件的目录,这里指定为当前目录
- –python_out:用于保存所生成代码(所有的 XXX_pb2.py)的目录,这里指定为当前目录
- –grpc_python_out:用于保存所生成代码(所有的 XXX_grpc_pb2.py)的目录,这里也是当前目录
注意这里的 pb2
是指生成代码遵循 Protocol Buffers Python API version2
,它和 Protocol Buffer Language
的版本无关(在 .proto
文件中通过 syntax = "proto3"
指定了 PB 版本为 version 3)。
命令执行成功后,可以在当前目录下看到两个新增的文件:
- hello_world_pb2.py:包含所生成的 request/response/service 类
- hello_world_pb2_grpc.py:包含所生成的 server/client 类
接下来我们需要在自己的代码中实现 rpc 方法,即在 rpc 方法中编写真实的业务逻辑。这里我们直接在自己的 gRPC server 文件中实现自己的 Greeter 类:
1 | from concurrent import futures |
- gRPC 自动生成的
helloworld_pb2_grpc.GreeterServicer
,定义了 RPC 接口 - 我们自己的 Greeter 类,它继承自
helloworld_pb2_grpc.GreeterServicer
,然后实现了其 RPC 方法SayHello
- 启动一个 grpc server,并向其添加
Greeter service
,开始接受客户端的 RPC 请求。 - gRPC 框架会负责对接收到的请求进行反序列化、执行 RPC方法、对响应进行序列化
然后在我们的 client 代码中,访问 Greeter
service 的 SayHello
接口:
1 | from __future__ import print_function |
- 创建一个 gRPC channel,该通道表示和 gRPC server 的网络连接
- 使用该 grpc Channel 初始化
helloworld_pb2_grpc.GreeterStub
- 客户端使用
helloworld_pb2_grpc.GreeterStub
访问 gRPC server 的 Greeter 服务 - gRPC 框架负责对请求进行序列化、发送请求消息、对应答消息进行反序列化
分别启动 server 和 client,程序运行符合预期:
1 | $ python server.py |