文章目录

  • 什么是协议缓冲区?
  • 如何定义协议缓冲区消息
  • 字段名称
  • 字段类型
  • 字段编号
  • 字段规则
  • 注释
  • protobuf 消息是如何压缩的?
  • protobuf 的优点
  • protobuf的缺点

协议缓冲区或 Protobuf 是一种二进制格式,由 Google 创建,用于序列化在服务之间传输的结构化数据。

在我们了解什么是协议缓冲区之前,让我们先了解一下 JSON。JSON 在数据交换格式方面显然具有很大的优势,例如:

  • 网络上广泛接受的格式
  • 可以被所有语言阅读
  • 可以通过网络轻松共享
  • 数据可以是任何类型(嵌套元素、数组等)
  • 人类可读

但它也有一些缺点:

  • 架构未强制执行
  • 由于重复的键,对象可能很大
  • 不支持评论、元数据或文档

牢记这些,现在让我们看一下 protobuf 是什么以及它如何尝试解决这些缺点。

什么是协议缓冲区?

官方页面:

协议缓冲区是 GOOGLE 用于序列化结构化数据的语言中立、平台中立、可扩展机制——想想 XML,但更小、更快、更简单。您只需定义一次数据的结构化方式,然后就可以使用特殊生成的源代码轻松地将结构化数据写入和读取各种数据流,并使用各种语言。

因此,协议缓冲区是一种有效编码结构化数据的方法。它提供了通过使用规范语言定义其模式来创建数据结构的灵活性。规范语言不是用任何语言编写的,您可以使用 proto 文件语法定义消息。

这些消息用于以特定格式对数据进行编码,以使消息大小更小。在了解优化之前,让我们先看一下模式定义本身。

如何定义协议缓冲区消息

让我们为博客文章定义一个消息定义。我们将在其上指定 3 个字段名称,标题、作者和正文。

syntax = "proto3";

message BlogPost {
  required title string = 1;
  required author string = 2;
  optional body string = 3;
}

这是在 .proto 文本文件中定义的。上面的消息定义中嵌入了很多功能。

字段名称

字段名称必须全部小写。这是 protoc 编译器规定的约定。

字段类型

我们通过指定字段名称的数据类型来获得完全类型化的数据,可以是标量类型(int32、bool、string、float 等)或复合类型,包括枚举类型和其他消息类型。

字段编号

右侧的数字是每个字段名称唯一的字段编号。正如我们之前所了解的,protobuf 将我们的数据转换为二进制格式,因此这些数字用于识别我们创建的二进制消息中的字段。一旦我们开始使用消息类型,就不应更改字段编号,因为这会导致向后兼容性问题。该数字可以在 1 到 2^29-1 的范围内。

字段规则

这些消息还分配有字段规则,让我们可以指定该字段是必需的、可选的还是重复的。重复字段用于定义数组或列表。

注释

我们还可以通过使用单行 (//) 和多行注释定义 (/* */) 在消息定义中添加文档。

这是一个类型的示例模式文件,我们不需要每次都手动创建它。它可以使用自动生成工具创建,具体取决于我们实现 protobuf 的编程语言。

其他需要了解的有用信息是:

  • 可以在同一个 .proto 文件中定义多种类型
  • 类型可以相互嵌套
  • 也可以在不同的 .proto 文件中导入类型(导入语句需要来自项目根目录的相对路径)

protobuf 消息是如何压缩的?

既然我们知道了如何为协议缓冲区消息创建模式,那么对它进行了哪些优化以使其比 XML 和 JSON 更快?

协议缓冲区的一个关键特性是它们将消息的上下文与消息包含的数据分开。

所以对于 JSON 消息:

{
  "author" : "saransh",
  "title" : "protobuf"
}

根据我们上面的消息定义,相应的协议缓冲区(为了我们的理解在字符串中)将是:

127saransh228protobuf

正如我们所看到的,protocol buffer 消息要短得多,并且不包含任何可以从 proto 文件本身推断出的额外元信息。因此,protobuf 消息更小,也更容易解析。另外,当它们转换为二进制时,它们会进一步提高性能。

输出消息的可读性较差,需要了解要破译的 protobuf 编码,但这是我们为提高效率而付出的代价。让我们打破 protobuf 消息以了解它的含义:

消息的每个段的结构如下:

{field_number}{field_type}{data}

字段编号是分配给 .proto 文件中的字段名称的编号。字段类型是我们为它定义的类型的表示。在我们的例子中,它是一个字符串,它是一个可变长度的字段。这也意味着将分配给该字段的值不是像整数那样的固定宽度构造。所以我们需要指定我们还必须提供下一个长度。从而"author": "saransh"变成127saransh。如果您想了解更多,可以在网站上详细阅读有关编码的更多信息。

因此,我们不需要携带字段的整个定义,只需要三个数字来定义消息的上下文以及字段映射到的值。因此,与其他序列化方法相比,整个过程在大小和速度方面都变得更加高效。

protobuf 的优点

  • 数据完全输入
  • 数据自动压缩
  • 文档可以嵌入到模式定义中
  • 语言不可知(所有主要语言都支持)
  • Schema 可以随着时间以安全的方式发展(确保向后兼容性)
  • 比 XML 小 3-10 倍,速度快 20-100 倍
  • 可以为您自动生成代码
  • 需要更少的用于数据类型检查的样板代码

protobuf的缺点

  • 需要Schema来生成代码和读取数据
  • 序列化数据不是人类可读的
  • 可能缺少对某些语言的支持(尽管其中大多数确实存在)

如果平台(例如发出 Web 请求)不支持协议缓冲区的二进制格式,则协议缓冲区中有能力将二进制消息序列化为字符串,以确保传输安全。这使得它也可用于这些场景,尽管协议缓冲区的大多数用例都围绕微服务和 gRPC 调用。

最后,需要考虑所有这些权衡并做出选择一件事而不是另一件事的决定。但是很高兴了解那里的各种技术,这篇文章旨在让您了解它。如果您喜欢这篇文章,请在下面发表评论,让我们知道!