grpc 核心概念、架构和生命周期

介绍关键的gRPC概念,概述gRPC架构和RPC生命周期。

不熟悉gRPC?请先阅读《gRPC简介》。关于特定语言的细节,请参见您所选择的语言的快速入门、教程和参考文档。

 

纵观全局
服务定义
像许多RPC系统一样,gRPC也是围绕着定义服务的理念,指定可以远程调用的方法及其参数和返回类型。默认情况下,gRPC使用协议缓冲区作为接口定义语言(IDL)来描述服务接口和有效载荷消息的结构。如果需要的话,也可以使用其他的替代品。

service HelloService {
  rpc SayHello (HelloRequest) returns (HelloResponse);
}

message HelloRequest {
  string greeting = 1;
}

message HelloResponse {
  string reply = 1;
}

gRPC让你定义四种服务方法。

单一的RPC,客户端向服务器发送一个请求,并得到一个响应,就像普通的函数调用一样。

rpc SayHello(HelloRequest) 返回(HelloResponse)。

服务器流式RPC,客户端向服务器发送一个请求,并得到一个流来读回一连串的消息。客户端从返回的流中读取信息,直到没有更多的信息。gRPC保证在单个RPC调用中的信息排序。

rpc LotsOfReplies(HelloRequest) 返回(stream HelloResponse)。

客户端流式RPC,客户端写了一连串的消息并将它们发送到服务器,同样使用一个提供的流。一旦客户端完成了消息的写入,它就等待服务器读取这些消息并返回其响应。gRPC再次保证了单个RPC调用中的消息排序。

rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);

双向流RPC,双方都使用读写流发送一连串的消息。这两个流独立运行,因此客户和服务器可以按照他们喜欢的顺序进行读写:例如,服务器可以等待收到所有客户的消息,然后再写它的响应,或者它可以交替地读一个消息然后写一个消息,或者其他一些读和写的组合。每个流中的消息的顺序被保留下来。

rpc BidiHello(stream HelloRequest) 返回(stream HelloResponse)。

你会在下面的RPC生命周期部分了解更多关于不同类型的RPC。

使用API
从.proto文件中的服务定义开始,gRPC提供了生成客户端和服务器端代码的协议缓冲区编译器插件。gRPC用户通常在客户端调用这些API,并在服务器端实现相应的API。

在服务器端,服务器实现服务所声明的方法,并运行gRPC服务器来处理客户端调用。gRPC基础设施对传入的请求进行解码,执行服务方法,并对服务响应进行编码。
在客户端,客户端有一个被称为存根的本地对象(对于某些语言,首选术语是客户端),它实现的方法与服务相同。然后,客户端就可以在本地对象上调用这些方法,将调用的参数包装在适当的协议缓冲区消息类型中--gRPC在向服务器发送请求并返回服务器的协议缓冲区响应后查看。
同步与异步
同步的RPC调用,在服务器的响应到达之前,是最接近于RPC所期望的过程调用的抽象的。另一方面,网络本身就是异步的,在许多情况下,能够在不阻塞当前线程的情况下启动RPC是非常有用的。

大多数语言中的gRPC编程API都有同步和异步两种类型。你可以在每种语言的教程和参考文档中找到更多信息(完整的参考文档即将推出)。

 

RPC的生命周期
在这一节中,你将仔细看看当gRPC客户端调用gRPC服务器方法时会发生什么。关于完整的实现细节,请参见特定语言的页面。

一元RPC
首先考虑最简单的RPC类型,即客户端发送一个请求并得到一个响应。

  1. 一旦客户端调用了一个存根方法,服务器就会被通知RPC已经被调用了,客户端的元数据为这个调用、方法名称和指定的最后期限(如果适用)。
  2. 然后,服务器可以直接发回自己的初始元数据(必须在任何响应之前发送),或者等待客户端的请求消息。哪种情况先发生,是特定的应用。
  3. 一旦服务器得到了客户端的请求消息,它就会做任何必要的工作来创建和填充一个响应。然后,响应会连同状态细节(状态代码和可选的状态信息)和可选的尾随元数据一起返回给客户(如果成功的话)。
  4. 如果响应状态是OK,那么客户端就会得到响应,这就完成了在客户端的调用。

 

服务器流RPC
服务器流RPC类似于单数RPC,只是服务器在响应客户端的请求时返回一个消息流。在发送完它的所有消息后,服务器的状态细节(状态代码和可选的状态消息)和可选的尾随元数据被发送到客户端。这就完成了在服务器端的处理。客户端一旦得到服务器的所有消息就完成了。

客户端流式RPC
客户端流式RPC类似于单数RPC,只是客户端向服务器发送一个消息流,而不是单个消息。服务器用一条消息(连同其状态细节和可选的尾随元数据)进行响应,通常但不一定是在它收到所有客户端的消息之后。

双向流RPC
在双向流RPC中,调用是由客户端调用方法和服务器接收客户端元数据、方法名称和最后期限发起的。服务器可以选择发回它的初始元数据或等待客户端开始流媒体消息。

客户端和服务器端的流处理是特定的应用。由于这两个流是独立的,客户端和服务器可以以任何顺序读写消息。例如,服务器可以等到收到客户端的所有消息后再写它的消息,或者服务器和客户端可以玩 "乒乓 "游戏--服务器得到一个请求,然后发回一个响应,然后客户端根据这个响应再发一个请求,如此反复。

 

最后期限/超时
gRPC允许客户指定在RPC以DEADLINE_EXCEEDED错误终止之前他们愿意等待多长时间完成RPC。在服务器端,服务器可以查询一个特定的RPC是否超时,或者还剩下多少时间来完成RPC。

指定最后期限或超时是由语言决定的:有些语言的API是以超时(时间长度)为单位工作的,而有些语言的API是以最后期限(一个固定的时间点)为单位工作的,可能有也可能没有默认的最后期限。

RPC终止
在gRPC中,客户端和服务器都对调用的成功做出独立的、本地的判断,他们的结论可能不一致。这意味着,例如,你可以有一个在服务器端成功完成的RPC("我已经发送了所有的响应!"),但在客户端却失败了("响应在我的最后期限之后到达!")。服务器也有可能在客户端发送完所有请求之前就决定完成。

取消一个RPC
客户端或服务器都可以在任何时候取消一个RPC。取消会立即终止RPC,这样就不会有进一步的工作了。

 Warning

Changes made before a cancellation are not rolled back.

元数据
元数据是关于特定RPC调用的信息(比如认证细节),以键值对的形式列出,其中键是字符串,值通常是字符串,但也可以是二进制数据。

键值不区分大小写,由ASCII字母、数字和特殊字符-、_、.组成,并且不能以grpc-开头(这些字符为gRPC本身所保留)。二进制值的键以-bin结尾,而ASCII值的键则没有。

元数据对gRPC本身是不透明的--它让客户端提供与调用服务器相关的信息,反之亦然。

对元数据的访问取决于语言。

通道
gRPC通道提供了一个与指定主机和端口上的gRPC服务器的连接。它是在创建客户端存根时使用的。客户端可以指定通道参数来修改gRPC的默认行为,比如打开或关闭消息压缩。一个通道有状态,包括连接和空闲。

gRPC如何处理关闭通道的问题取决于语言。有些语言也允许查询通道状态。

 

 

posted @ 2022-09-29 16:52  风在何方  阅读(203)  评论(0编辑  收藏  举报