2021-11-02

gRPC使用实例

1 gRPC介绍

A high-performance, open-source universal RPC framework

所谓RPC(remote procedure call 远程过程调用)框架实际是提供了一套机制,使得应用程序之间可以进行通信,而且也遵从server/client模型。使用的时候客户端调用server端提供的接口就像是调用本地的函数一样。如下图所示就是一个典型的RPC结构图。
在这里插入图片描述

gRPC有什么好处以及在什么场景下需要用gRPC

既然是server/client模型,那么我们直接用restful api不是也可以满足吗,为什么还需要RPC呢?下面我们就来看看RPC到底有哪些优势

gRPC vs. Restful API

gRPC和restful API都提供了一套通信机制,用于server/client模型通信,而且它们都使用http作为底层的传输协议(严格地说, gRPC使用的http2.0,而restful api则不一定)。不过gRPC还是有些特有的优势,如下:

  • gRPC可以通过protobuf来定义接口,从而可以有更加严格的接口约束条件。关于protobuf可以参见笔者之前的小文Google Protobuf简明教程
  • 另外,通过protobuf可以将数据序列化为二进制编码,这会大幅减少需要传输的数据量,从而大幅提高性能。
  • gRPC可以方便地支持流式通信(理论上通过http2.0就可以使用streaming模式, 但是通常web服务的restful api似乎很少这么用,通常的流式数据应用如视频流,一般都会使用专门的协议如HLS,RTMP等,这些就不是我们通常web服务了,而是有专门的服务器应用。)
使用场景
  • 需要对接口进行严格约束的情况,比如我们提供了一个公共的服务,很多人,甚至公司外部的人也可以访问这个服务,这时对于接口我们希望有更加严格的约束,我们不希望客户端给我们传递任意的数据,尤其是考虑到安全性的因素,我们通常需要对接口进行更加严格的约束。这时gRPC就可以通过protobuf来提供严格的接口约束。
  • 对于性能有更高的要求时。有时我们的服务需要传递大量的数据,而又希望不影响我们的性能,这个时候也可以考虑gRPC服务,因为通过protobuf我们可以将数据压缩编码转化为二进制格式,通常传递的数据量要小得多,而且通过http2我们可以实现异步的请求,从而大大提高了通信效率。
  • 但是,通常我们不会去单独使用gRPC,而是将gRPC作为一个部件进行使用,这是因为在生产环境,我们面对大并发的情况下,需要使用分布式系统来去处理,而gRPC并没有提供分布式系统相关的一些必要组件。而且,真正的线上服务还需要提供包括负载均衡,限流熔断,监控报警,服务注册和发现等等必要的组件。不过,这就不属于本篇文章讨论的主题了,我们还是先继续看下如何使用gRPC。

2 gRPC实例

2.1 安装环境
pip install grpcio
pip install grpcio-tools googleapis-common-protos

gRPC由两个部分构成,grpcio 和 gRPC 工具, 后者是编译 protocol buffer 以及提供生成代码的插件。

2.2 gRPC的使用通常包括如下几个步骤:
  1. 通过protobuf来定义接口和数据类型
  2. 生成接口代码
  3. 编写gRPC server端代码
  4. 编写gRPC client端代码
    在这里插入图片描述
1 通过protobuf来定义接口和数据类型
syntax = 'proto3';
package rpc_package;

// define a service 定义一个service
service Sampling {
  // define the interface and data type 定义接口和数据类型
  // 采样请求与返回
  rpc Sampling (SamplingRequest) returns (SamplingResponse) {}
  // 训练模型的请求和返回
  rpc TrainModel (TrainModelRequest) returns (TrainModelResponse) {}
}

// 采样请求数据
message SamplingRequest  {
  string str_data = 1;
  string msg = 2;
}

// 采样响应数据
message SamplingResponse {
    string msg = 1;
}

// 训练模型请求数据
message TrainModelRequest  {
  int32 data_num = 1;
  string msg = 2;
}

// 训练模型响应数据
message TrainModelResponse  {
  string str_data = 1;
  string msg = 2;
}

service TrainModel {
  // 采样请求与返回
  rpc SaveTrainModel (SaveTrainModelRequest) returns (SaveTrainModelResponse) {}
  // 训练模型的请求和返回
  rpc GetTrainModel (GetTrainModelRequest) returns (GetTrainModelResponse) {}
}

// 保存训练模型请求
message SaveTrainModelRequest {
  string file=1;
  string name=2;
}

// 保存训练模型响应
message SaveTrainModelResponse {
  string msg=1;
}

// 获取训练模型请求
message GetTrainModelRequest {
  string msg=1;
}

// 获取训练模型请求
message GetTrainModelResponse {
  string file=1;
  string name=2;
}
2 生成接口代码
python -m grpc_tools.protoc --proto_path=./protos --python_out=./rpc_package --grpc_python_out=./rpc_package ./protos/sampling.proto

在这里插入图片描述

3 编写gRPC server端代码
class SamplingServer(SamplingServicer):
    def __init__(self):
        self.sampling_buffer = []
        self.num = 0

    def Sampling(self, request, context):
        # 逻辑处理
        msg = 'ok'
        return SamplingResponse(msg=f'{msg}')
        
def server():
    # 这里通过thread pool来处理并发server的任务
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10), options=[
                ('grpc.max_send_message_length', GRPC_MAX_MESSAGE_LENGTH),
                ('grpc.max_receive_message_length', GRPC_MAX_MESSAGE_LENGTH),
            ])
    # 将对应的任务处理函数添加到rpc server中
    add_SamplingServicer_to_server(SamplingServer(), server)
    # 这里使用非安全接口,世界gRPC支持TLS/SSL安全连接,以及各种鉴权机制
    server.add_insecure_port(f'[::]:{sampling_port}')
    server.start()
    try:
        while True:
            time.sleep(60 * 60 * 24)
    except KeyboardInterrupt:
        server.stop(0)

注意:
grpc.max_send_message_length, grpc.max_receive_message_length 设置接收发送文件大小,默认4M,大于4M要要设置

4 编写gRPC client端代码
def run_sampling_client_send_obs_and_actions(str_data):
    # 使用with语法保证channel自动关闭options=(('grpc.enable_http_proxy', 0),)
    with grpc.insecure_channel(
            f'{sampling_host}:{sampling_port}',
            options=[
                ('grpc.max_send_message_length', GRPC_MAX_MESSAGE_LENGTH),
                ('grpc.max_receive_message_length', GRPC_MAX_MESSAGE_LENGTH),
            ]
    ) as channel:
        # 客户端通过stub来实现rpc通信
        stub = SamplingStub(channel)
        msg = 'ok'
        # 客户端必须使用定义好的数据类型,这里是Request类型
        stub.Sampling(SamplingRequest(str_data=str_data, msg=msg))

注意:客户端也要定义,有人说只要定义服务端就行,但是我编写的过程中,接收没问题,发送仍然存在文件太大问题,定义客户端解决了问题。
grpc.max_send_message_length, grpc.max_receive_message_length 设置接收发送文件大小,默认4M,大于4M要要设置

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值