本篇文章是在学习gRPC框架的过程中翻译的官方文档,非作者原创,官方文档参考gRPC,学习gRPC过程中,有些概念,思想理解翻译不到位还请多多指教。
本文通过回顾gRPC整体架构和RPC的生命周期来介绍gRPC中一些重要概念。
本文假定读者已经阅读过什么是gRPC。本文不具体讲解gRPC与具体语言相关的实现细节,这个部分内容读者可以参考。
概述
服务定义
和其他RPC系统一样,服务定义也是gRPC的基础,gRPC默认使用protocol buffers作为接口定义语言(IDL)来定义服务接口和负载信息的结构,gRPC支持使用其他方法进行服务定义。一个简单的HelloService服务定义如下:
service HelloService {
rpc SayHello (HelloRequest) returns (HelloResponse);
}
message HelloRequest {
string greeting = 1;
}
message HelloResponse {
string reply = 1;
}
gRPC支持定义四种类型的方法:
- 一元RPC方法:客户端发起一个请求,从服务端得到一个响应,和普通函数调用相似。
rpc SayHello(HelloRequest) returns (HelloResponse){
}
- 服务端返回流RPC方法:客户端发起一个请求,从服务端得到一个消息流,客户端可以一直从流中读取数据直到读取完服务端返回的所有数据。
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse){
}
- 客户端发送流RPC方法:客户端向请求中写入流并发送给服务端,客户端发送完全部数据,客户端会使用相同的流获取服务端的返回。
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse) {
}
- 双向流RPC方法:客户端和服务端都可以使用读-写流发送一系列消息。读、写流的操作互相独立,客户端和服务端都可以按照各自的顺序读写数据。服务端响应客户端的三种方式:1、读完所有请求,然后返回响应;2、边读边发送响应;3、1和2的任意组合。读写流中数据的顺序保持不变。
rpc BidiHello(stream HelloRequest) returns (stream HelloResponse){
}
API 使用
API
使用.proto文件定义一个服务,gRPC提供protocol buffer编译插件来生成客户端和服务端代码,服务端实现API,客户端调用API。
- 服务端:服务端需要实现.proto中定义的方法,并启动一个gRPC服务器用于处理客户端请求。gRPC反序列化到达的请求,执行服务方法,序列化服务端响应并发送给客户端。
-
客户都:客户端本地有一个实现了服务端一样方法的对象,gRPC中称为桩,其他语言中更习惯称为客户端。客户调用本地桩的方法,将参数按照合适的协议封装并将请求发送给服务端,并接收服务端的响应。
请求-响应模型
同步vs异步
在服务器返回响应前,同步RPC调用将阻塞客户端当前线程,同步RPC调用与gRPC的抽象过程调用模型最接近。从另一方面来看,网络本质上是异步的,在许多情况下,能够在不阻塞当前线程的情况下进行RPC调用非常有用。大多数编程语言对应的gRPC接口都同时支持异步和同步RPC调用。
RPC 的生命周期
更进一步,进入gRPC内部,了解客户端调用API的过程中究竟发生了什么。
一元RPC
一元RPC是最简单的RPC模型,在一元RPC中客户端发送一个请求并从服务端得到一个响应。
- 一旦客户端调用了桩/客户端对象的方法,服务端将会收到方法被调用的通知,并从中得到客户端调用方法的元信息,方法名和最后期限(尽可能获取)
- 服务器可以选择直接响应服务器自己的初始元信息(必须在发送响应前发送)或者等待客户端请求到达,服务器选择哪种方式,由应用配置决定的。
- 服务器收到客户端请求,服务端就会执行创建和填充响应所需的任何工作。然后将响应(如果成功)连同状态详细信息(状态代码和可选状态消息)和可选的跟踪数据一起返回给客户端。
-
如果请求状态是OK,客户端可以收到来自服务端的响应,整个请求-响应过程在客户端侧完成。
一元RPC
服务端流RPC
服务端流RPC模型和简单的一元RPC模型类似,在服务端接收到客户端请求后,服务端返回一个响应流。当服务端发送完所有数据后,服务端状态详情(状态码和可选的状态新)和可选的跟踪元数据会返回给客户端,然后RPC请求-响应在服务端完成。一旦服务端发送完所有数据,客户端即完成。
客户端流RPC
该RPC模型下,客户端发送一个请求流而不是单一请求,服务端通常在接收完客户端请求后连同状态详细信息,跟踪元数据和响应一起返回给客户端,服务端可以选择返回状态信息和跟踪信息。
双向流RPC
在双向流RPC模型中,客户端RPC调用后,服务端接收到客户端元信息、方法名和最后期限。服务端可以选择马上发送自己的元信息给客户端,或者等待客户端请求的到达。
完成以上动作后,接下来的处理动作依赖应用程序,客户端和服务端可以以任意的顺序进行读写操作,流的操作完全互相独立。举个例子,服务端可能接收完所有客户端数据后再写响应到流中,或者客户端和服务端进行“ping-pong”操作,服务端接收到一个请求,然后返回一个响应,客户端根据响应的内容选择发送下一个请求,如此反复执行。
Deadlines/Timeouts
gRPC允许客户端设置等待RPC完成的时间(RPC因发生错误而结束前),在服务端,可以查询特定的RPC是否超时,剩余时间。然而不同编程语言之间对最后期限和超时时间的描述各异,有些编程语言通过时间点控制,有写编程语言通过时间段控制。.
RPC 终止
在gRPC框架中,客户端和服务端都可以独立的、单方面决定RPC 调用是否成功,客户端和服务端对同一个RPC调用的最终结果可能不一致。这意味这,比如,一个RPC调用在服务端是成功(服务端已经发送所有响应),但是RPC调用在客户端失败(响应到达时间超时)。服务端也有可能在客户端发送完所有数据前将当前RPC调用设置为完成。
取消 RPC
客户端和服务端可以在任何时间取消RPC调用,取消会立即终止RPC调用(不会执行其他动作),所以在RPC调用取消前,不会回滚任何操作。
元数据
元数据是特定RPC调用的信息(例如鉴权信息),元信息通常是键-值对的列表,键的类型为字符串,值的类型一般也为字符串,但是值可以是二进制数据。元数据对gRPC框架本身是不透明的——它允许客户端与服务器调与RPC调用相关的信息
获取元数据的方法依赖于语言。
通道
在创建客户端桩时,gRPC通过可以提供一个连接特点地址端口的服务端的连接,客户端可以通过参数来修改通道默认行为,比如是否开启信息压缩。通道是由状态的,比如已连接,空闲。gRPC如何处理通过的关闭是与语言相关的,有些语言支持查询通道的状态。