gRPC学习与应用(1)

本文介绍了gRPC的基本原理、优势及适用场景,并详细讲解了如何使用ProtocolBuffers定义数据和服务,探讨了gRPC的核心概念,包括服务定义、同步与异步调用、RPC生命周期等。
Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

一、gRPC简介[1]

1.概述

gRPC是RPC(Remote Procedure Call)框架中的一种,是一个高性能开源通用的RPC框架。它使用Protocol buffers作为其接口定义语言(Interface Definition Launguage, IDL)以及信息交换格式,支持众多开发语言,包括C# / .NETC++DartGoJavaKotlinNodeObjective-CPHPPythonRuby等。

在gPRC里,客户端可以直接调用另一台不同机器上服务端应用的方法,就像调用本地对象一样,使得我们能够更容易地创建分布式应用和服务。

与其他多种RPC系统一样,gRPC也是通过定义“服务”以及“可以远程调用的方法及其参数与返回值”实现远程调用的(实际上也就是消息协议和远程调用接口)。这些接口在服务端被实现,以便处理客户端的远程调用。而客户端则保留有一个存根(stub),该存根提供服务端的可以被远程调用的相同的接口。实际上也就是对远程服务调用进行了代理封装,所有关于网络通信相关的内容在代理中进行处理。

gRPC的交互过程如下:代理向外部提供可以直接调用的方法接口(不同语言实现的接口),通过将接口调用转换为通信消息发送,再到服务端接收解析通信消息,在服务端完成相应方法调用,再将处理后的结果通过通信返回给客户端,客户端解析通信消息,将解析出的消息结果作为被调用方法的返回值返回给调用方。通过这样的过程,就实现了调用方像调用本地对象一样调用远程方法。
gRPC基本原理

gRPC基本原理

gRPC的优势[2]

  • 性能: gRPC使用的Protocol Buffers在服务端和客户端上的序列化非常快。Protocol Buffers序列化后的消息体积很小,能够有效负载,这在移动应用程序等有限带宽场景中显得很重要。

  • 代码生成: 通过在服务器和客户端之间共享*.proto文件,可以从端到端生成消息和客户端代码。客户端的代码生成消除了客户端和服务器上的重复消息,并为您创建了一个强类型的客户端。无需编写客户端代码,可在具有许多服务的应用程序中节省大量开发时间。

  • 严格的规范: 该gRPC规范是规定有关gRPC服务必须遵循的格式。gRPC消除了争论并节省了开发人员的时间,因为gPRC在各个平台和实现之间是一致的。

  • 流: HTTP/2为长期的实时通信流提供了基础。gRPC通过HTTP/2为流媒体提供一流的支持。

  • 截至时间/超时和取消: gRPC允许客户端指定他们愿意等待RPC完成的时间。该期限被发送到服务端,服务端可以决定在超出了限期时采取什么行动。(有助于实施资源使用限制)

gRPC的劣势

  • 浏览器支持有限,当下不可能直接从浏览器调用gRPC服务。gRPC Web是gRPC团队的一项附加技术,它在浏览器中提供有限的gRPC支持。但gRPC Web并非支持所有gRPC功能。不支持客户端和双向流,并且对服务器流的支持有限。

  • 传输数据时二进制流,且格式不可读。需要额外的工具来分析线路上的Protobuf有效负载,并手工编写请求。

gRPC适合使用场景

gRPC非常适合以下场景:

  • 微服务 - gRPC设计为低延迟和高吞吐量通信。gRPC非常适用于效率至关重要的轻型微服务。
  • 点对点实时通信 - gRPC对双向流媒体提供出色的支持。gRPC服务可以实时推送消息而无需轮询。
  • 多语言混合开发环境 - gRPC工具支持所有流行的开发语言,使gRPC成为多语言开发环境的理想选择。
  • 网络受限环境 - 使用Protobuf(一种轻量级消息格式)序列化gRPC消息。gRPC消息始终小于等效的JSON消息。

gRPC不建议使用场景

在以下场景中,建议使用其他框架而不是gRPC:

  • 浏览器可访问的API - 浏览器不完全支持gRPC。gRPC-Web可以提供浏览器支持,但它有局限性并引入了服务器代理。
  • 广播实时通信 - gRPC支持通过流媒体进行实时通信,但不存在向已注册连接广播消息的概念。例如,在应该将新聊天消息发送到聊天室中的所有客户端的聊天室场景中,需要每个gRPC呼叫以单独地将新的聊天消息流传输到客户端。对于这种场景,SignalR是这种情况的有用框架。SignalR具有持久连接的概念和对广播消息的内置支持。
  • 进程间通信 - 进程必须承载HTTP/2服务才能接受传入的gRPC调用。对于Windows,进程间通信管道是一种快速,轻量级的通信方法。

2.使用Protocol Buffers通信

gRPC默认使用谷歌成熟的开源协议Protocol Buffers来序列化结构化数据(尽管gRPC也可以使用类似JSON的数据格式)。

相比较而言,Protobuf有如下优点[3]

  • 足够简单
  • 序列化后体积很小:消息大小只需要XML的1/10 ~ 1/3
  • 解析速度快:解析速度比XML快20 ~ 100倍
  • 多语言支持
  • 更好的兼容性,Protobuf设计的一个原则就是要能够很好的支持向下或向上兼容

protobuf 有2个版本,默认版本是proto2,如果需要proto3,则需要在非空非注释第一行使用 syntax = "proto3" 标明版本。相比于proto2版本,proto3略微简化了语法、提供了一些新的特性,并支持了更多语言。

2.1 数据结构定义

使用Protocol Buffers的第一步是在以.proto为后缀的proto文件中定义所需要传输数据的结构。Protocol Buffers数据是按照消息的结构进行结构化的,每一个消息都是由一系列键值对构成的小的信息单元,例如:

message Person {
  string name = 1;
  int32 id = 2;
  bool has_ponycopter = 3;
}

采用上述格式定义好数据结构后,在能够使用之前,我们还需要使用protoc编译指令,对上述数据结构进行编译,将其编译为我们所选的编程语言可以用来访问数据的类。这个编译成的类,可以实现对域值(field)的访问以及结构数据的序列化(编译成字节)和反序列化(从字节解析)。

2.2 gRPC服务定义

与数据结构的定义类似,gRPC服务在以.proto为后缀的proto文件中定义,包括参数和返回值类型(数据结构)的定义,例如

// Greeter服务定义
service Greeter {
  // SayHello方法定义(参数类型、返回值类型)
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// 服务参数数据结构定义
message HelloRequest {
  string name = 1;
}

// 服务返回值数据结构定义
message HelloReply {
  string message = 1;
}

通过使用protoc对上述proto文件进行编译,将得到生成的gRPC客户端和服务端源码,以及可以用于填充、序列化和检索消息类型的常规protocol buffer代码。

二、核心概念

1.服务定义

在前面,我们介绍了gRPC中数据结构和服务的定义(在以.proto为后缀的proto文件中),gRPC支持四种服务方法的定义:

gRPC服务支持所有流组合:

(1)一元(没有流媒体)

简单rpc 这就是一般的rpc调用,一个请求对象对应一个返回对象。客户端发起一次请求,服务端响应一个数据,即标准RPC通信。

rpc SayHello(HelloRequest) returns (HelloResponse);

(2)服务器到客户端流(客户端流式rpc)

客户端传入多个请求对象,服务端返回一个响应结果。应用场景:物联网终端向服务器报送数据。

rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);

(3)客户端到服务器流(服务端流式rpc)

一个请求对象,服务端可以传回多个结果对象。服务端流 RPC 下,客户端发出一个请求,但不会立即得到一个响应,而是在服务端与客户端之间建立一个单向的流,服务端可以随时向流中写入多个响应消息,最后主动关闭流,而客户端需要监听这个流,不断获取响应直到流关闭。应用场景举例:典型的例子是客户端向服务端发送一个股票代码,服务端就把该股票的实时数据源源不断的返回给客户端。

rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);

(4)双向流媒体(双向流式rpc)

结合客户端流式rpc和服务端流式rpc,可以传入多个对象,返回多个响应对象。应用场景:聊天应用。

rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);

2.同步调用 vs. 异步调用

同步RPC调用将阻塞直至调用响应从服务端到达,是最为接近过程调用的方式。然而由于网络内生是异步的,并且在很多场景下,非阻塞式调用是十分有用的。因此,gRPC对大多数编程语言的API接口同时支持同步调用异步调用模式。

3.RPC生命周期

四种流组合模式下的RPC生命周期参见参考资料[1]中关于RPC生命周期部分的介绍,其中:

  • 一元(没有流媒体)模式下,交互过程与传统的socket通信基本类似。

  • 服务端流式rpc模式下,服务端会向客户端发送一系列响应消息后,其向客户端发送状态详细信息(包括状态码和可选的状态消息)以及可选的结尾元数据。

  • 客户端流式rpc模式下,客户端会发送一系列消息到服务端,服务端通过单一消息响应客户端(包括状态详细信息以及可选的结尾元数据),但也可能不会等到收完客户端发送的所有消息。

  • 双向流式rpc模式下,调用过程从客户端激活调用方法初始,服务端接收客户端的元数据、方法名称以及截止时间。而后,服务端可以选择是否发送初始元数据或者等待客户端开始发送消息流(因具体应用而异)。

关于截止时间和超时:gRPC允许客户端通过DEADLINE_EXCEEDED错误设置RPC等待时间,同时,支持服务端查询一个RPC过程是否超时或者还剩下多少时间。

4.元数据

元数据是特定RPC调用的信息(如身份验证详细信息),其形式为键值对列表,其中键是字符串,值通常是字符串,但也可以是二进制数据。

元数据对gRPC本身是不透明的——它允许客户端向服务器提供与调用相关的信息,反之亦然。对元数据的访问取决于语言。

5.通道

gRPC通道提供到指定主机和端口上的gRPC服务器的连接,在创建客户端存根时使用。客户端可以指定通道参数来修改gRPC的默认行为,例如打开或关闭消息压缩。通道具有状态,包括connectedidle。gRPC如何处理关闭通道取决于语言。某些语言还允许查询通道状态。

通过上述学习,我们大致上了解了gRPC的基本情况、核心概念以及使用方式。下面,我们将通过实际开发进一步了解和研究gRPC的使用。

参考资料

[1] Introduction to gRPC | gRPC

[2] GRPC简介 - 知乎 (zhihu.com)

[3] Google Protobuf简明教程 - 简书

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值