python|python gRPC

python|python gRPC
文章图片
react_js.jpg 【python|python gRPC】最近在用 python 写项目,项目中有许多 AI 服务需要相互调用,为了服务之间的解耦合,想尝试采用 gRPC 来进行服务之间相互调用。之所以考虑采用 gRPC 这种方式来在不同服务之间传递数据,主要是出于对于性能有更高的要求的考虑。而且 AI 的服务需要传递大量的数据(图像数据),而又希望不影响性能,所以最终想尝试采用 gRPC,具体来看一下 gRPC 是如何解决性能问题。在 gRPC 中,通过 protobuf ,可以将数据压缩编码转化为二进制格式,通常传递的数据量要小得多,而且通过 http2 ,可以实现异步的请求,从而大大提高了通信效率。说了这么多我们看一看如何使用 gRPC,
RPC RPC(Remote Procedure Call)远程过程调用,简单的理解是一个节点请求另一个节点提供的服务。如果 http 就是一种远程调用的协议。这里提到了远程过程调用,那么对于远程就应该有本地过程调用那么什么是本地过程调用,也就是调用本地方法对本地的对象进行操作。例如调用 Add 方法向列表中添加一个对象。而远程过程调用,向列表添加对象方法并不在本地,调用远程提供 Add() 来实现该操作。
安装

pip install grpcio-tools pip install grpc

快速入门 其实首先我们需要定义 service ,这里类似我们对服务说明书,这个文件以proto扩展名结尾,在其中定义服务(service),在服务中提供方法(rpc) 每一个方法有两参数一个请求体参数,一个是响应体参数,这里点和我们平时写 http 服务很相似,还需要定义写请求体和响应体的数据类型。总体来看类似一个说明书,把 rpc 服务相关的内容都记录这里,然后就可以通过 grpc_tools.protoc 工具会根据这个proto文件生成两个 python 文件。
定义服务(service) service 关键字随后是服务名称,通常准照驼峰命名规则。
service HelloWord{}

接下来在 service 内定义方法,方法名前需要添加关键字 rpc 表示,在 grpc 中提供了 4 种类型的方法供我们来选择使用。
比较简单 RPC 方法是客户端使用 stub 向服务端发起请求,然后等待服务端响应返回值,这个和一般我们了解的 web 请求没有什么区别
rpc GetFeature(Point) returns (Feature) {}

response-streaming RPC 方式是客户端发起请求到服务端后,服务端处理请求会以流形式返回消息给客户端,客户端通过流的形式读取返回信息。要实现这种方式请求,与普通请求不同之处需要在响应体前添加 stream
rpc ListFeatures(Rectangle) returns (stream Feature) {}

request-streaming RPC 方式是指在客户端将以序列形式组织要送的消息,然后以流形式发送给客户端,一旦客户端完成写入消息到序列后,就只需要等待服务端返回值,在这种请求方式,需要在请求体前添加 stream
rpc RecordRoute(stream Point) returns (RouteSummary) {}

bidirectionally-streaming RPC 通过读写流实现服务端和客户端之间通讯,服务端和客户端可以按一定顺序相互读取消息。服务端可以在接收所有客户端消息后,返回响应给客户端,这样可以交替在客户端和服务器端间读写消息,要实现双向通讯,需要在请求体和响应体之前都添加关键字 stream
$ python -m grpc_tools.protoc -I../../protos --python_out=. --grpc_python_out=. ../../protos/route_guide.proto

运行命令会自动生成route_guide_pb2.pyroute_guide_pb2_grpc.py两个文件
其中生成来 route_guide.proto 中定义的 message 类和定义的 service 类,代码中 RouteGuideStub 用于在客户端调用 RouteGuide RPC 提供的功能,在 RouteGuideServicer 中定义了 RouteGuide 服务需要实现方法,route_guide.proto 中定义 add_RouteGuideServicer_to_server 用于将 RouteGuideServicer 服务添加到 grpc 中,
创建服务端(server)
接下来是看如何创建服务端,要创建一个服务端有两件事需要做:
需要实现之前定义好的接口方法,在其中实现具体逻辑
Request-streaming RPC
运行 gRPC 服务来监听客户端请求,然后返回响应值
def serve(): server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) route_guide_pb2_grpc.add_RouteGuideServicer_to_server( RouteGuideServicer(), server) server.add_insecure_port('[::]:50051') server.start() server.wait_for_termination()

在 start() 方法是无阻塞的,因为会实例化一个新的线程来处理客户端的请求,在启动后不会同时做其他任务,
创建客户端(client) 有了服务端,接下来就可以创建向客户端发起请求的的客户端,如果在客户端想要调用服务端的方法,就需要在客户端stub,可以实例化一个 RouteGuideStub,这个方法是由刚刚使用命令通过 proto 文件生成的route_guide_pb2_grpc所提供的方法。
channel = grpc.insecure_channel('localhost:50051') stub = route_guide_pb2_grpc.RouteGuideStub(channel)

对于返回单个响应的 RPC 方法(响应方法),grpc python 同时支持同步(阻塞)和异步(非阻塞)两种方式来控制方法间数据传输。对于响应流RPC 的方法,调用立即返回响应迭代器。调用迭代器的 next() 方法来获取值。

    推荐阅读