gRPC 核心概念、架构与生命周期
核心概念、架构与生命周期
本文介绍 gRPC 核心概念,并概述 gRPC 架构与 RPC 生命周期。
。有关语言特定细节,请查看你所选语言的快速入门、教程与参考文档。
概述
服务定义
与许多 RPC 系统类似,gRPC 基于定义服务的思想:指定可以被远程调用的方法,以及它们的参数和返回类型。默认情况下,gRPC 使用Protocol Buffers作为Interface Definition Language (IDL),用于描述服务接口以及消息负载结构。也可以使用其他替代方案。
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:客户端发送一个请求,然后获得一个流来读取一系列消息。gRPC 保证单次 RPC 内的消息顺序。
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);- 客户端流式 RPC:客户端使用一个流写入一系列消息并发送给服务端。客户端写完消息后,会等待服务端读取完成并返回响应。gRPC 同样保证单次 RPC 内的消息顺序。
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);- 双向流式 RPC:双方都使用读写流发送一系列消息。这两个流相互独立运行,因此客户端和服务端可以按照任意顺序读写。每个流内部的消息顺序会被保留。
rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);你将在下面RPC 生命周期部分更详细地了解这些 RPC 类型。
API 使用
从.proto文件中的服务定义开始,gRPC 提供protoc插件,用于生成客户端和服务端代码。gRPC 用户通常在客户端调用这些 API,并在服务端实现对应的 API。
- 服务端:实现服务中声明的方法,并运行 gRPC 服务器处理客户端调用。gRPC 底层框架负责解码入站请求、执行服务方法、编码服务响应。
- 客户端:拥有一个名为stub的本地对象(在某些语言中也叫 client),它实现了与服务相同的方法。你可以在客户端直接调用这个本地对象上的方法,这些方法会将参数封装成对应的 Protocol Buffers 消息类型,向服务端发送请求,并接收服务端返回的 Protocol Buffers 响应。
同步与异步
同步 RPC 调用会一直阻塞,直到收到服务端响应,这最接近 RPC 所追求的过程调用抽象。但由于网络本身是异步的,在很多场景下,发起 RPC 而不阻塞当前线程非常有用。
大多数语言中的 gRPC 编程 API 同时提供同步和异步两种形式。具体细节可以参考各语言的教程和参考文档。
RPC 生命周期
本节详细介绍当 gRPC 客户端调用服务端方法时发生的流程。具体实现细节请查阅对应语言的文档。
一元 RPC
先看最简单的 RPC 类型:客户端发送单个请求,获得单个响应。
- 客户端调用 stub 上的方法后,服务端会收到此次调用的相关通知,包括此次调用的metadata、方法名,以及指定的deadline(如果有)。
- 服务端可以选择立刻发送回自己的初始 metadata(必须在任何响应之前发送),或者等待客户端的请求消息,具体取决于应用逻辑。
- 服务端收到客户端的请求消息后,会执行相关逻辑生成并填充响应。响应成功后,服务端会连同状态详情(状态码、可选状态信息)以及可选的trailing metadata一起返回给客户端。
- 如果响应状态是
OK,客户端会收到响应,客户端侧的调用就此完成。
服务端流式 RPC
服务端流式 RPC 与一元 RPC 类似,区别在于服务端返回的是一个消息流,而不是单个消息。服务端在发送完所有消息后,会发送状态详情和可选的 trailing metadata 给客户端,完成服务端侧的处理。客户端在读完所有消息后,调用结束。
客户端流式 RPC
客户端流式 RPC 也与一元 RPC 类似,区别在于客户端发送给服务端的是消息流,而不是单个消息。服务端通常(但不必须)在收到客户端所有消息后,返回一个单独的响应(附带状态详情和可选 trailing metadata)。
双向流式 RPC
在双向流式 RPC 中,调用由客户端发起调用方法开始,服务端接收到客户端的 metadata、方法名和 deadline。
服务端可以选择返回初始 metadata,或者等待客户端开始发送消息流。
客户端和服务端的流处理完全由应用决定。由于两个流相互独立,客户端和服务端可以以任意顺序读写消息。例如:服务端可以等待收到所有客户端消息后再回复;或者双方交替读写 —— 服务端接收一条请求、返回一条响应,客户端再根据响应发送下一条请求,以此类推。
Deadline / Timeout
gRPC 允许客户端指定一个 RPC 完成的最大等待时间。超时后 RPC 会以DEADLINE_EXCEEDED错误终止。服务端可以查询某个 RPC 是否已经超时,或者还剩多少时间。
Deadline 和 timeout 的设置方式因语言而异:部分语言 API 使用 timeout(时长),部分使用 deadline(固定时间点),部分语言有默认 deadline。
RPC 终止
在 gRPC 中,客户端和服务端对调用是否成功的判断是本地且独立的,结果可能不一致。例如:服务端已经成功完成所有响应发送,但客户端因为超时认为调用失败。服务端也可能在客户端发送完所有请求前就终止 RPC。
取消 RPC
客户端或服务端都可以在任意时刻取消 RPC。取消会立即终止 RPC,不再进行后续操作。
警告取消之前已经执行完成的操作不会回滚。
Metadata
Metadata 是一次 RPC 调用相关的信息(例如认证相关数据),以键值对列表形式存在:key 是字符串,value 通常是字符串,也可以是二进制数据。
Key 不区分大小写,由 ASCII 字母、数字和-、_、.组成,并且不能以grpc-开头(gRPC 保留前缀)。二进制值对应的 key 以-bin结尾,普通 ASCII 值的 key 则没有此后缀。
用户自定义 metadata 不由 gRPC 本身使用,用于客户端向服务端传递与调用相关信息,或服务端向客户端传递信息。
Metadata 的访问方式因语言而异。
Channel
gRPCChannel提供与指定主机和端口上的 gRPC 服务端的连接,用于创建客户端 stub。客户端可以配置 Channel 参数修改 gRPC 默认行为,例如开启或关闭消息压缩。Channel 具有状态,包括connected和idle。
关闭 Channel 的方式因语言而异,部分语言支持查询 Channel 状态。
