gRPC 官方文档html
gRPC 是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。编程
gRPC 基于 HTTP/2 标准设计,带来诸如双向流、流控、头部压缩、单 TCP 链接上的多复用请求等特。json
这些特性使得其在移动设备上表现更好,更省电和节省空间占用。api
gRPC 一开始由 google 开发,是一款语言中立、平台中立、开源的远程过程调用(RPC)系统。安全
在 gRPC 里客户端应用能够像调用本地对象同样直接调用另外一台不一样的机器上服务端应用的方法,使得您可以更容易地建立分布式应用和服务。服务器
与许多 RPC 系统相似,gRPC 也是基于如下理念:定义一个服务,指定其可以被远程调用的方法(包含参数和返回类型)。网络
在服务端实现这个接口,并运行一个 gRPC 服务器来处理客户端调用。架构
在客户端拥有一个存根可以像服务端同样的方法。并发
gRPC 客户端和服务端能够在多种环境中运行和交互 - 从 google 内部的服务器到你本身的笔记本,而且能够用任何 gRPC 支持的语言来编写。app
因此,你能够很容易地用 Java 建立一个 gRPC 服务端,用 Go、Python、Ruby 来建立客户端。
此外,Google 最新 API 将有 gRPC 版本的接口,使你很容易地将 Google 的功能集成到你的应用里。
经过对于 gRPC 的架构和 RPC 生命周期的概览来介绍 gRPC 的主要概念。
正如其余 RPC 系统,gRPC 基于以下思想:定义一个服务, 指定其能够被远程调用的方法及其参数和返回类型。
gRPC 默认使用 protocol buffers 做为接口定义语言,来描述服务接口和有效载荷消息结构。若是有须要的话,可使用其余替代方案。
gRPC 容许你定义四类服务方法:
gRPC 提供 protocol buffer 编译插件,可以从一个服务定义的 .proto 文件生成客户端和服务端代码。一般 gRPC 用户能够在服务端实现这些API,并从客户端调用它们。
同步 RPC 调用一直会阻塞直到从服务端得到一个应答,这与 RPC 但愿的抽象最为接近。另外一方面网络内部是异步的,而且在许多场景下可以在不阻塞当前线程的状况下启动 RPC 是很是有用的。
在多数语言里,gRPC 编程接口同时支持同步和异步的特色。你能够从每一个语言教程和参考文档里找到更多内容(很快就会有完整文档)。
首先咱们来了解一下最简单的 RPC 形式:客户端发出单个请求,得到单个响应。
服务端流式 RPC 除了在获得客户端请求信息后发送回一个应答流以外,与咱们的简单例子同样。在发送完全部应答后,服务端的状态详情(状态码和可选的状态信息)和可选的跟踪元数据被发送回客户端,以此来完成服务端的工做。客户端在接收到全部服务端的应答后也完成了工做。
客户端流式 RPC 也基本与咱们的简单例子同样,区别在于客户端经过发送一个请求流给服务端,取代了原先发送的单个请求。服务端一般(但并没必要须)会在接收到客户端全部的请求后发送回一个应答,其中附带有它的状态详情和可选的跟踪数据。
双向流式 RPC ,调用由客户端调用方法来初始化,而服务端则接收到客户端的元数据,方法名和截止时间。服务端能够选择发送回它的初始元数据或等待客户端发送请求。 下一步怎样发展取决于应用,由于客户端和服务端能在任意顺序上读写 - 这些流的操做是彻底独立的。例如服务端能够一直等直到它接收到全部客户端的消息才写应答,或者服务端和客户端能够像"乒乓球"同样:服务端后获得一个请求就回送一个应答,接着客户端根据应答来发送另外一个请求,以此类推。
gRPC 容许客户端在调用一个远程方法前指定一个最后期限值。这个值指定了在客户端能够等待服务端多长时间来应答,超过这个时间值 RPC 将结束并返回DEADLINE_EXCEEDED
错误。在服务端能够查询这个期限值来看是否一个特定的方法已通过期,或者还剩多长时间来完成这个方法。 各语言来指定一个截止时间的方式是不一样的 - 好比在 Python 里一个截止时间值老是必须的,但并非全部语言都有一个默认的截止时间。
在 gRPC 里,客户端和服务端对调用成功的判断是独立的、本地的,他们的结论可能不一致。这意味着,好比你有一个 RPC 在服务端成功结束("我已经返回了全部应答!"),到那时在客户端多是失败的("应答在最后期限后才来到!")。也可能在客户端把全部请求发送完前,服务端却判断调用已经完成了。
不管客户端仍是服务端都可以再任什么时候间取消一个 RPC 。一个取消会当即终止 RPC 这样能够避免更多操做被执行。它不是一个"撤销", 在取消前已经完成的不会被回滚。固然,经过同步调用的 RPC 不能被取消,由于直到 RPC 结束前,程序控制权尚未交还给应用。
元数据是一个特殊 RPC 调用对应的信息(受权详情]) ,这些信息以键值对的形式存在,通常键的类型是字符串,值的类型通常也是字符串(固然也能够是二进制数据)。元数据对 gRPC 本事来讲是不透明的 - 它让客户端提供调用相关的信息给服务端,反之亦然。 对于元数据的访问是语言相关的。
TBD
TBD
在建立客户端存根时,一个 gRPC 频道提供一个特定主机和端口服务端的链接。客户端能够经过指定频道参数来修改 gRPC 的默认行为,好比打开关闭消息压缩。一个频道具备状态,包含已链接
和空闲
。 gRPC 如何处理关闭频道是语言相关的。有些语言可容许询问频道状态。
gRPC 被设计成能够利用插件的形式支持多种受权机制。本文档对多种支持的受权机制提供了一个概览,而且用例子来论述对应API,最后就其扩展性做了讨论。
gRP 集成 SSL/TLS 并对服务端受权所使用的 SSL/TLS 进行了改良,对客户端和服务端交换的全部数据进行了加密。
对客户端来说提供了可选的机制提供凭证来得到共同的受权。
gRPC 提供通用的机制(后续进行描述)来对请求和应答附加基于元数据的凭证。
当经过 gRPC 访问 Google API 时,会为必定的受权流程提供额外的获取访问令牌的支持,这将经过如下代码例子进行展现。 警告:Google OAuth2 凭证应该仅用于链接 Google 的服务。把 Google 对应的 OAuth2 令牌发往非 Google 的服务会致使令牌被窃取用做冒充客户端来访问 Google 的服务。
为了减小复杂性和将混乱最小化, gRPC 以一个统一的凭证对象来进行工做。 凭证能够是如下两类:
频道
上, 好比 SSL 凭证。客户端上下文
)。
组合频道凭证
来进行组合。组合频道凭证
能够将一个频道凭证
和一个调用凭证
关联建立一个新的频道凭证
。调用凭证
来做为受权数据。
频道凭证
能够由一个Ssl 凭证
和一个访问令牌凭证
生成。结果是在这个频道上的每次调用都会发送对应的访问令牌。 调用凭证
能够用 组合凭证
来组装。组装后的 调用凭证
应用到一个客户端上下文
里,将触发发送这两个调用凭证
的受权数据。
如下是 gRPC 请求和应答消息流中通常的消息顺序:
请求 → 请求报头 *界定的消息 EOS 请求报头是经过报头+联系帧方式以 HTTP2 报头来发送的。
请求报头 → 调用定义 *自定义元数据
调用定义 → 方法模式路径TE [受权] [超时] [内容类型] [消息类型] [消息编码] [接受消息类型] [用户代理]
方法 → “:method POST”
模式 → “:scheme ” (“http” / “https”)
路径 → “:path” {开放的 API 对应的方法路径}
Authority → “:authority” {受权的对应的虚拟主机域名}
TE → “te” “trailers” # 用来检测不兼容的代理
超时 → “grpc-timeout” 超时时间值 超时时间单位
超时时间值 → {至少8位数字正整数的 ASCII 码字符串}
超时时间单位 → 时 / 分 / 秒 / 毫秒 / 微秒 / 纳秒
时 → “H”
分 → “M”
秒 → “S”
毫秒 → “m”
微秒 → “u”
纳秒 → “n”
内容类型 → “content-type” “application/grpc” [(“+proto” / “+json” / {自定义})]
内容编码 → “gzip” / “deflate” / “snappy” / {自定义}
消息编码 → “grpc-encoding” Content-Coding
接受消息编码 → “grpc-accept-encoding” Content-Coding *("," Content-Coding)
用户代理 → “user-agent” {结构化的用户代理字符串}
消息类型 → “grpc-message-type” {消息模式的类型名}
自定义数据 → 二进制报头 / ASCII 码报头
二进制报头 → {以“-bin”结尾小写的报头名称的 ASCII 码 } {以 base64 进行编码的值}
ASCII 码报头 → {小写报头名称的 ASCII 码} {值}
界定的消息的重复序列经过数据帧来进行传输。
界定的消息 → 压缩标志 消息长度 消息
压缩标志 → 0 / 1 # 编码为 1 byte 的无符号整数
消息长度 → {消息长度} # 编码为 4 byte 的无符号整数
消息 → *{二进制字节}
应答 → (应答报头 界定的消息 跟踪信息) / 仅仅跟踪
应答报头 → HTTP 状态 [消息编码] [消息接受编码] 内容类型 *自定义元数据
仅仅跟踪 → HTTP 状态 内容类型 跟踪消息
跟踪消息 → 状态 [状态消息] *自定义元数据
HTTP状态 → “:status 200”
状态 → “grpc-status” <状态码的 ASCII 字符串>
状态消息 → “grpc-message” <状态描述文本对应的 ASCII 字符串>
全部的 GRPC 调用须要定义指定一个内部 ID。咱们将在这个模式里使用 HTTP2 流 ID 来做为调用标识。注意:这些 ID 在一个打开的 HTTP2 会话里是先后关联的,在一个处理多个 HTTP2 会话的进程里不是惟一的,也不能被用做 GUID。
数据帧边界与界定消息的边界无关,实现时不该假定它们有一致性。
当应用错误或运行时错误在 PRC 调用过程当中出现时,状态和状态消息应当经过跟踪消息发送。
HTTP2 规范当使用 TLS 时强制使用 TLS 1.2 及以上的版本,而且在部署上对容许的密码施加一些额外的限制以免已知的好比须要 SNI 支持的问题。而且期待 HTTP2 与专有的传输安全机制相结合,这些传输机制的规格说明不能提供有意义的建议。
服务端发出这种帧给客户端表示服务端在相关的链接上再也不接受任何新流。这种帧包含服务端最后成功接受的流的ID。客户端应该认为任何在最后成功的流后面初始化的任意流为 UNAVAILABLE,而且在别处重试这些调用。客户端能够自由地在已经接受的流上继续工做直到它们完成或者链接中断。 服务端应该在终止链接前发送 GOAWAY 帧,以可靠地通知客户端哪些工做已经被服务端接受并执行。
客户端和服务端都可以发送一个 PING 帧,对方必须精确回显它们所接收到的信息。这能够被用来确认链接仍然是活动的,而且可以提供估计端对端延迟估计的方法。假如服务端初始的 PING 在最后期限仍然没有收到运行时所期待的应答的话,全部未完成的调用将会被以取消状态关闭。一个客户端期满的初始的PING则会致使全部的调用被以用不可用状态关闭。注意PING的频率高度依赖于网络环境,实现能够根据网络和应用须要,自由地调整PING频率。
假如客户端检测到链接失败,全部的调用都会被以不可用状态关闭。而服务端侧则全部已经打开的调用都会被以取消状态关闭。