gRPC

gRPC 是什么可以用官网的一句话来概括

“A high-performance, open-source universal RPC framework”

  • 多语言:语言中立,支持多种语言。
  • 轻量级、高性能:序列化支持 PB(Protocol Buffer)JSONPB 是一种语言无关的高性能序列化框架。
  • 可插拔
  • IDL:基于文件定义服务,通过 proto3 工具生成指定语言的数据结构、服务端接口以及客户端 Stub
  • 设计理念
  • 移动端:基于标准的 HTTP2 设计,支持双向流、消息头压缩、单 TCP 的多路复用、服务端推送等特性,这些特性使得 gRPC 在移动端设备上更加省电和节省网络流量。

image.png

  • 服务而非对象、消息而非引用:促进微服务的系统间粗粒度消息交互设计理念。
  • 负载无关的:不同的服务需要使用不同的消息类型和编码,例如 protocol buffersJSONXMLThrift
  • 流: Streaming API
  • 阻塞式和非阻塞式:支持异步和同步处理在客户端和服务端间交互的消息序列。
  • 元数据交换:常见的横切关注点,如认证或跟踪,依赖数据交换。
  • 标准化状态码:客户端通常以有限的方式响应 API 调用返回的错误。

不要过早关注性能问题,先标准化。

  1. protoc --go_out=. --go_opt=paths=source_relative \
  2. --go-grpc_out=. --go-grpc_opt=paths=source_relative \
  3. helloworld/helloworld.proto

image.png

API Project

https://github.com/googleapis/googleapis https://github.com/envoyproxy/data-plane-api https://github.com/istio/api

为了统一检索和规范 API,我们内部建立了一个统一的 bapis 仓库,整合所有对内对外 API

  • API 仓库,方便跨部门协作。
  • 版本管理,基于 git 控制。
  • 规范化检查,API lint
  • API design review,变更 diff
  • 权限管理,目录 OWNERS

image.png

API Project Layout

项目中定义 proto,以 api 为包名根目录:
image.png
在统一仓库中管理 proto ,以仓库为包名根目录:
image.png
image.png

API Compatibility

向后兼容(非破坏性)的修改

  • API 服务定义添加 API 接口

    从协议的角度来看,这始终是安全的。

  • 给请求消息添加字段

    只要客户端在新版和旧版中对该字段的处理不保持一致,添加请求字段就是兼容的。

  • 给响应消息添加字段

    在不改变其他响应字段的行为的前提下,非资源(例如,ListBooksResponse)的响应消息可以扩展而不必破坏客户端的兼容性。即使会引入冗余,先前在响应中填充的任何字段应继续使用相同的语义填充。

向后不兼容(破坏性)的修改

  • 删除或重命名服务,字段,方法或枚举值

    从根本上说,如果客户端代码可以引用某些东西,那么删除或重命名它都是不兼容的变化,这时必须修改major 版本号。

  • 修改字段的类型

    即使新类型是传输格式兼容的,这也可能会导致客户端库生成的代码发生变化,因此必须增加 major 版本号。 对于编译型静态语言来说,会容易引入编译错误。

  • 修改现有请求的可见行为

    客户端通常依赖于 API 行为和语义,即使这样的行为没有被明确支持或记录。 因此,在大多数情况下,修改 API 数据的行为或语义将被消费者视为是破坏性的。如果行为没有加密隐藏,您应该假设用户已经发现它,并将依赖于它。

  • 给资源消息添加 读取/写入 字段

API Naming Conventions

包名为应用的标识(APP_ID),用于生成 gRPC 请求路径,或者 proto 之间进行引用 Message。文件中声明的包名称应该与产品和服务名称保持一致。带有版本的 API 的软件包名称必须以此版本结尾。
image.png

my.package.v1,为 API 目录,定义 service 相关接口,用于提供业务使用。

  1. // RequestURL: /<package_name>.<version>.<service_name>/{method}
  2. package <package_name>.<version>;

image.png

API Primitive Fields

gRPC 默认使用 Protobuf v3 格式,因为去除了 required optional 关键字,默认全部都是 optional 字段。如果没有赋值的字段,默认会基础类型字段的默认值,比如 0 或者 “”。

Protobuf v3 中,建议使用:https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/wrappers.proto Warpper 类型的字段,即包装一个 message,使用时变为指针。

image.png
image.png

image.png
Protobuf 作为强 schema 的描述文件,也可以方便扩展,是不是用于配置文件定义也可?

API Errors

使用一小组标准错误配合大量资源

  • 例如,服务器没有定义不同类型的“找不到”错误,而是使用一个标准 google.rpc.Code.NOT_FOUND 错误代码并告诉客户端找不到哪个特定资源。状态空间变小降低了文档的复杂性,在客户端库中提供了更好的惯用映射,并降低了客户端的逻辑复杂性,同时不限制是否包含可操作信息(/google/rpc/error_details)。

错误传播

如果您的 API 服务依赖于其他服务,则不应盲目地将这些服务的错误传播到您的客户端。在翻译错误时,我们建议执行以下操作:

  • 隐藏实现详细信息和机密信息。
  • 调整负责该错误的一方。例如,从另一个服务接收 INVALID_ARGUMENT 错误的服务器应该将 INTERNAL 传播给它自己的调用者。

image.png

全局错误码

全局错误码,是松散、易被破坏契约的,基于我们上述讨论的,在每个服务传播错误的时候,做一次翻译,这样保证每个服务 + 错误枚举,应该是唯一的,而且在 proto 定义中是可以写出来文档的。
image.png

image.png

API Design

image.png
image.png
FieldMask 部分更新的方案:
• 客户端可以执行需要更新的字段信息:

  1. paths: "author"
  2. paths: "submessage.submessage.field"

FieldMask 默认应用到 “所有字段”

image.png参考链接

https://cloud.google.com/apis/design