gRPC|青训营笔记

89 阅读5分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 20 天
gRPC是谷歌开源的一款高性能、支持多种开发语言的服务框架,对于一个rpc我们关注如下几方面:

序列化协议gRPC使用protobuf,首先使用protobuf定义服务,然后使用这个文件来生成客户端和服务端的代码。因为pb是跨语言的,因此即使服务端和客户端语言并不一致也是可以互相序列化和反序列化的

网络传输层。gRPC使用http2.0协议,http2.0相比于HTTP 1.x ,大幅度的提升了 web 性能。

image-20220328002124007-8398087.png

Protobuf IDL

所谓序列化通俗来说就是把内存的一段数据转化成二进制并存储或者通过网络传输,而读取磁盘或另一端收到后可以在内存中重建这段数据

1、protobuf协议是跨语言跨平台的序列化协议。

2、protobuf本身并不是和gRPC绑定的。它也可以被用于非RPC场景,如存储等

json xml都是一种序列化的方式,只是他们不需要提前预定义idl,且具备可读性,当然他们传输的体积也因此较大,可以说是各有优劣

所以先来介绍下protobuf的idl怎么写。protobuf最新版本为proto3,在这里你可以看到详细的文档说明:protobuf.dev/programming…

定义消息类型

protobuf里最基本的类型就是message,每一个messgae都会有一个或者多个字段(field),其中字段包含如下元素

protobuf类型格式.drawio.png

  • 类型:类型不仅可以是标量类型(intstring等),也可以是复合类型(enum等),也可以是其他message

  • 字段名:字段名比较推荐的是使用下划线/分隔名称

  • 字段编号:一个messgae内每一个字段编号都必须唯一的,在编码后其实传递的是这个编号而不是字段名

  • 字段规则:消息字段可以是以下字段之一

    • singular:格式正确的消息可以有零个或一个字段(但不能超过一个)。使用 proto3 语法时,如果未为给定字段指定其他字段规则,则这是默认字段规则
    • optional:与 singular 相同,不过您可以检查该值是否明确设置
    • repeated:在格式正确的消息中,此字段类型可以重复零次或多次。系统会保留重复值的顺序
    • map:这是一个成对的键值对字段
  • 保留字段:为了避免再次使用到已移除的字段可以设定保留字段。如果任何未来用户尝试使用这些字段标识符,编译器就会报错

标量值类

标量类型会涉及到不同语言和编码方式,后续有机会深入讲

.proto TypeGo TypeNotes
doublefloat64
floatfloat32
int32int32使用可变长度的编码。对负数的编码效率低下 - 如果您的字段可能包含负值,请改用 sint32。
int64int64使用可变长度的编码。对负数的编码效率低下 - 如果字段可能有负值,请改用 sint64。
uint32uint32使用可变长度的编码。
uint64uint64使用可变长度的编码。
sint32int32使用可变长度的编码。有符号整数值。与常规 int32 相比,这些函数可以更高效地对负数进行编码。
sint64int64使用可变长度的编码。有符号整数值。与常规 int64 相比,这些函数可以更高效地对负数进行编码。
fixed32uint32始终为 4 个字节。如果值通常大于 2^28,则比 uint32 更高效。
fixed64uint64始终为 8 个字节。如果值通常大于 2^56,则比 uint64 更高效。
sfixed32int32始终为 4 个字节。
sfixed64int64始终为 8 个字节。
boolbool
stringstring字符串必须始终包含 UTF-8 编码或 7 位 ASCII 文本,并且长度不得超过 232。
bytes[]byte可以包含任意长度的 2^32 字节。

复合类型

数组

message SearchResponse {
  repeated Result results = 1;
}

message Result {
  string url = 1;
  string title = 2;
  repeated string snippets = 3;
}
复制代码

枚举

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
  enum Corpus {
    UNIVERSAL = 0;
    WEB = 1;
    IMAGES = 2;
    LOCAL = 3;
    NEWS = 4;
    PRODUCTS = 5;
    VIDEO = 6;
  }
  Corpus corpus = 4;
}
复制代码

服务

定义的method仅能有一个入参和出参数。如果需要传递多个参数需要定义成message

service SearchService {
  rpc Search(SearchRequest) returns (SearchResponse);
}
复制代码

使用其他消息类型

使用import引用另外一个文件的pb

syntax = "proto3";

import "google/protobuf/wrappers.proto";

package ecommerce;

message Order {
  string id = 1;
  repeated string items = 2;
  string description = 3;
  float price = 4;
  google.protobuf.StringValue destination = 5;
}
复制代码

protoc使用

protoc就是protobuf的编译器,它把proto文件编译成不同的语言

📖 安装

grpc.io/docs/protoc…

  • Linux, using apt or apt-get, for example:

    $ apt install -y protobuf-compiler
    $ protoc --version  # Ensure compiler version is 3+
    复制代码
    
  • MacOS, using Homebrew:

    $ brew install protobuf
    $ protoc --version  # Ensure compiler version is 3+
    复制代码
    

📖 使用

$ protoc --help
Usage: protoc [OPTION] PROTO_FILES

  -IPATH, --proto_path=PATH   指定搜索路径
  --plugin=EXECUTABLE:
  
  ....
 
  --cpp_out=OUT_DIR           Generate C++ header and source.
  --csharp_out=OUT_DIR        Generate C# source file.
  --java_out=OUT_DIR          Generate Java source file.
  --js_out=OUT_DIR            Generate JavaScript source.
  --objc_out=OUT_DIR          Generate Objective C header and source.
  --php_out=OUT_DIR           Generate PHP source file.
  --python_out=OUT_DIR        Generate Python source file.
  --ruby_out=OUT_DIR          Generate Ruby source file
  
   @<filename>                proto文件的具体位置
复制代码

1.搜索路径参数

第一个比较重要的参数就是搜索路径参数,即上述展示的-IPATH, --proto_path=PATH。它表示的是我们要在哪个路径下搜索.proto文件,这个参数既可以用-I指定,也可以使用--proto_path=指定。

如果不指定该参数,则默认在当前路径下进行搜索;另外,该参数也可以指定多次,这也意味着我们可以指定多个路径进行搜索。

2.语言插件参数

语言参数即上述的--cpp_out=--python_out=等,protoc支持的语言长达13种,且都是比较常见的

运行help出现的语言参数,说明protoc本身已经内置该语言对应的编译插件,我们无需安装

作者:凉凉的知识库
链接:juejin.cn/post/719100…
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。