体验 gRPC 那些事儿

概述

我们来看 google 对于 gRPC 的定义:

A high performance, open-source universal RPC framework

即 gRPC 是一个开源的高性能通过 RPC 框架。具体来说,它具有以下特点:

  • 使用 protocol buffers 来作为序列化和反序列化,以及接口定义语言 (IDL)
  • 跨语言,跨平台,gRPC支持多种平台和多种语言,这应该是 gRPC 框架最大的优势
  • 易于使用,安装编译环境和运行环境
  • 基于 HTTP/2 ,提供双向传输和认证机制

对于 gRPC 的应用场景,google 给出了一些常见的应用情景,个人则认为更适合于内部服务的使用。

关于 protobuf,多说一下。gRPC 将服务接口的定义写在 .proto 文件中,.proto 文件遵循 protobuf 的规范。使用 gRPC 提供的命令行工具,可以对 .proto 文件进行编译成相关语言的源代码,例如 c++ 语言或者 python 语言的服务端和客户端代码 。

安装

以 python 版本的 gRPC 为例,说明 gRPC 的安装。

1) 将 pip 的版本升级到最新版本

1
pip install --upgrade pip

2)安装 grpcio 包

1
pip install grpcio

3)安装 gRPC 的 python 工具包

1
pip install grpcio-tools

4)下载 gRPC 的官方例子

1
2
git clone https://github.com/grpc/grpc
cd grpc/examples/python/helloworld

下载的例子在 gPRC 源代码的 examples 目录中。

使用

环境已安装完毕,接下来便可以运行代码了。进入 examples/python/helloworld 目录。
运行服务端程序,服务端监听 50051端口。

1
python greeter_server.py

打开另一个终端,运行客户端程序,

1
python greeter_client.py

可以看到客户端程序的输出

Greeter client received: Hello, you!

说明客户端通过 gRPC 成功从服务端获取了数据。

分析

正常使用 gRPC 的流程是,我们需要首先编写接口和消息的声明文件 .proto,然后进行编译才可以得到相应接口和消息的源文件。上面我们省略了编译的操作,是由于 gRPC 的源代码中已经将 examples 目录下的例子都编译好了。

打开 examples/protos/helloworld.proto,可以看到原来的接口和消息声明为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
string name = 1;
}

// The response message containing the greetings
message HelloReply {
string message = 1;
}

.proto 文件包括两部分的声明,分别是接口的声明和消息的声明。原来已经有一个接口 SayHello,假设现在我们需要增加一个接口 SayHelloAgain,新接口的参数和返回值使用原有的类型,那么新的 .proto 文件如下:

1
2
3
4
5
6
7
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
// Sends another greeting
rpc SayHelloAgain (HelloRequest) returns (HelloReply) {}
}

编写或者更新 .proto 文件后,需要对其进行编译。上面我们安装了 grpcio-tools 工具,可以对 .proto 文件编译。

1
2
cd examples/python/helloworld
python -m grpc_tools.protoc -I../../protos --python_out=. --grpc_python_out=. ../../protos/helloworld.proto

执行命令后会生成新的 helloworld_pb2.py 文件和新的 helloworld_pb2_grpc.py 文件。helloworld_pb2.py 文件包含生成的请求类和响应类,而 helloworld_pb2_grpc.py 文件则包含生成的服务端骨架(skeleton)代码和客户端桩(stub)代码。

为了使用新的接口 SayHelloAgain ,需要在我们的程序代码增加新的测试代码。
服务端程序:

1
2
3
4
5
6
class Greeter(helloworld_pb2_grpc.GreeterServicer):
def SayHello(self, request, context):
return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name)

def SayHelloAgain(self, request, context):
return helloworld_pb2.HelloReply(message='Hello again, %s!' % request.name)

客户端程序:

1
2
3
4
5
6
7
8
def run():
channel = grpc.insecure_channel('localhost:50051')
stub = helloworld_pb2_grpc.GreeterStub(channel)
response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'))
print("Greeter client received: " + response.message)

response = stub.SayHelloAgain(helloworld_pb2.HelloRequest(name='you'))
print("Greeter client received: " + response.message)

最后我们再次执行新的服务端和客户端程序。可以看到,客户端终端中,增加了一行输出:

Greeter client received: Hello, you!
Greeter client received: Hello again, you!

说明我们成功添加了新的接口。

参考资料

  1. http://www.grpc.io
  2. https://http2.github.io/
  3. http://www.grpc.io/docs/quickstart/python.html
  4. http://www.integralist.co.uk/posts/grpc.html