python grpc 使用

  |   源代码

grpc 是google开发的远程通信协议,和它最相近的产品的产品是apache基金会下的thrift协议。

两者都是很优秀的通信中间件产品,拥有很好的性能,支持大多数主要语言。

相对于thrift协议,更年轻,更轻量,grpc基于http2传输协议和protocol buffer(也可以使用json)序列化协议。

这也带来相对于thrfit的优点:

  1. http2相对于thrfit的tcp协议更容易扩展,参见1:
    • 相对于http1.x,http2采用二进制传输,同时多次请求时会对http协议的header信息进行压缩,从而大幅提高http2的性能
    • 多路复用/请求流控制,相对于http1是同步请求,一个链接同一时间只能处理一个请求。http2是完全异步请求, 在同一个tcp链接上客户端和服务端可以同时进行多次请求响应。
    • 基于多路复用和请求流控制,通过新增了一个带stream参数的流化或者类似于管道通信功能,这一点和通常的rpc协议差别很大, 不管在服务端实现上还是客户端调用上都和常规的rpc请求不同,后面的例子中可以具体看到这种差异.
    • 易于扩展,例如:在异构系统(例如微服务系统)中,一次真是的客户端请求发生了,实际在发生很多次的服务间调用, 使用http协议可以方便的扩展,增加调用堆栈/流信息,方便日志记录。
  2. protocol buffer 本身是一个独立的高性能序列化协议,在程序内部能够有很好的通用性,可以直接作为内部数据的表示方式,也可以直接 用于缓存数据。

如下简单看下,如何使用python创建grpc服务。

参考官方的地图导航例子: [[https://github.com/grpc/grpc/blob/v1.24.0/examples/protos/route_guide.proto]grpc router guide]]

创建.proto

创建.proto文件:

vi router_guide.proto

编辑以下内容:

syntax = "proto3";

// 下面是生成java代码需要的声明
option java_multiple_files = true;
option java_package = "io.grpc.examples.routeguide";
option java_outer_classname = "RouteGuideProto";

// objectc 选项
option objc_class_prefix = "RTG";

// 很多语言都需要的生成代码的目标包(python,go,java 等)或者命名空间(c++)
package routeguide;

// 定义接口.
service RouteGuide {
  // 第一个简单非流化rpc接口 单向通信,客户端传入一个位置,服务端返回这个位置的兴趣点
  rpc GetFeature(Point) returns (Feature) {}

  // 单向流化接口
  // 服务端返回结果流化接口 
  // 获取置顶矩形区域内的所有兴趣
  // 因为返回的结果可能会很多 所以结果不是一次返回,而是流化的,类似于服务端通过管道将返回的
  rpc ListFeatures(Rectangle) returns (stream Feature) {}

  // 单向流化接口 
  // 客户端输入参数流化接口
  // 传入一个流化的位置集合,等所有流化参数都传输玩了,服务端一次性 返回路由汇总信息
  rpc RecordRoute(stream Point) returns (RouteSummary) {}

  // 双向流化接口
  // 在双向流化接口中 客户端的输入流化参数和server端的返回流化结果,客户端和同时完全异步的相互“推送信息”
  rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
}

// 位置点
message Point {
  // 纬度*10的7次方 
  int32 latitude = 1;
  // 精度*10的7次方 
  int32 longitude = 2;
}

// 矩形区域 两个位置点为 对角线,生成一个矩形区域
message Rectangle {
  Point lo = 1;

  Point hi = 2;
}

// 兴趣点
message Feature {
  string name = 1;
  Point location = 2;
}

// A RouteNote is a message sent while at a given point.
message RouteNote {
  // The location from which the message is sent.
  Point location = 1;

  // The message to be sent.
  string message = 2;
}

// A RouteSummary is received in response to a RecordRoute rpc.
//
// It contains the number of individual points received, the number of
// detected features, and the total distance covered as the cumulative sum of
// the distance between each point.
message RouteSummary {
  // The number of points received.
  int32 point_count = 1;

  // The number of known features passed while traversing the route.
  int32 feature_count = 2;

  // The distance covered in metres.
  int32 distance = 3;

  // The duration of the traversal in seconds.
  int32 elapsed_time = 4;
}

编译

安装grpcio-tools

pip install grpcio-tools

编译:

python -m grpc_tools.protoc -I./ --python_out=. --grpc_python_out=. route_guide.proto

编译会生成两个文件,$package_name+"_pb2.py" 和 $package_name + "_pb2_grpc.py", 前者实现了结构体的序列化协议,后者实现了grpc的通信接口。

(需要注意的是生成的_pb2这个后缀表示的pb对于的python pb api的实现版本,不是pb IDL语言协议的"proto3")

编写server-client代码

client 样例:

server 样例:

运行演示

cd ../files/python-grpc/

python demo.py > output.log

输出:

grpc stream 说明

grpc stream 概念和管道的概念很相似,grpc 输入的stream参数,相当于客户端链接服务端的一个管道, 返回的stream参数相当于服务端连接到客户端的管道。这样不管是客户端还是服务端在一次请求中,可以完全异步的进行通信。

在一次请求中, 对客户端来说,可以一边发送数据到服务端,同时也可以接受服务端的返回结果.

Footnotes:

Comments powered by Disqus