python grpc 使用
grpc 是google开发的远程通信协议,和它最相近的产品的产品是apache基金会下的thrift协议。
两者都是很优秀的通信中间件产品,拥有很好的性能,支持大多数主要语言。
相对于thrift协议,更年轻,更轻量,grpc基于http2传输协议和protocol buffer(也可以使用json)序列化协议。
这也带来相对于thrfit的优点:
- http2相对于thrfit的tcp协议更容易扩展,参见1:
- 相对于http1.x,http2采用二进制传输,同时多次请求时会对http协议的header信息进行压缩,从而大幅提高http2的性能
- 多路复用/请求流控制,相对于http1是同步请求,一个链接同一时间只能处理一个请求。http2是完全异步请求, 在同一个tcp链接上客户端和服务端可以同时进行多次请求响应。
- 基于多路复用和请求流控制,通过新增了一个带stream参数的流化或者类似于管道通信功能,这一点和通常的rpc协议差别很大, 不管在服务端实现上还是客户端调用上都和常规的rpc请求不同,后面的例子中可以具体看到这种差异.
- 易于扩展,例如:在异构系统(例如微服务系统)中,一次真是的客户端请求发生了,实际在发生很多次的服务间调用, 使用http协议可以方便的扩展,增加调用堆栈/流信息,方便日志记录。
- 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参数相当于服务端连接到客户端的管道。这样不管是客户端还是服务端在一次请求中,可以完全异步的进行通信。
在一次请求中, 对客户端来说,可以一边发送数据到服务端,同时也可以接受服务端的返回结果.