Protobuf 为啥比 JSON、XML 牛
原创

Protobuf 为啥比 JSON、XML 牛

好文
试试语音读文章

热门答案:

今天。我带大家更深层次的认识认识 Protobuf。如果你对 Protobuf 的用法还不熟悉。直接前往:developers.google.com/protocol-bu…。

当对 Protobuf 有了基本的认识后。就会明白了 Protobuf 序列化的数据会比 JSON、XML 传输效率更高。

那为啥会高呢?本篇就带着这个问题一探究竟。

看表面

对于 JSON、XML。为了便于数据传输时的可阅读性。会保留数据的结构化信息。举个 JSON 例子。如下:

{
  "name": "laomiao",
  "age": 18
}
复制代码

当发送该信息时。接受方收到后就会明白。这是个 “key/value” 形式的数据。并且”name” 后是姓名。”age” 后是年龄。

那如何压缩该数据呢?

我们可以删除 “花括号”、“name”、“age” 以及其它的 “冒号”、“逗号”、“引号” 等结构数据。

laomiao18
复制代码

那这样删除了。接收方怎么知道。哪个是姓名?哪个是年龄?

删除 ”结构“

只需要发送方和接收方都保留这份数据的 ”结构“ 就行。发送方只发送数据。接收方接收到数据后。根据本地保留的 ”结构“ 去解析数据就 OK。

假设。该 “结构” 如下。这不是真实存在的。只是为了方便给大家描述。

{
  name string 7
  age int 1
}
复制代码

通过该 ”结构“ 就可以知道:

  • name 数据在 age 数据之前。
  • name 数据类型为 string。age 数据类型为 int。
  • name 数据字节长度为 7。age 数据字节长度为 1。

接收方只需要拿着这份 ”结构“ 就知道了 “laomiao18” 数据如何解析。

自描述

但这样还是有这些问题:

  1. name 数据如果超过 7 个字节怎么办?
  2. age 数据超过 1 个字节怎么办?
  3. 结构中的顺序不能调整。太死了。怎么办?

当然。发送方和接收方都更新下自己的 ”结构“ 数据。但这样显然不现实。因为数据你不能保证是固定长度。

对于 age 数据。我们可以定义为 4 个字节或 8 个字节。只要可以应对自己的业务即可。但这样还是有问题。空间浪费?

假如。age 定义为 4 个字节。传输的数据为 18。而对于 18 这个数字。只需要 1 个字节就足以了。而剩下 3 个字节都浪费着。但咱又不能定义为 1 个字节。因为有可能会有大数。

那如何压缩 age 数据呢?

对于 Protobuf。会在数据中加入解决以上问题的信息。即数据自己描述自己。简称 ”自描述“。

总结下 Protobuf 做了哪些?如下:

  • 数据中加入 ”字段“ 顺序的信息。
  • 数据中加入类型信息。
  • 最小化压缩整形数据。

Protobuf

Protobuf 在序列化数据时。将 Protobuf 数据类型总共划分为 6 大类。英文称为 “wire type”。

wire typeproto 类型含义0int32, int64, uint32, uint64, sint32, sint64, bool, enumVarint1fixed64, sfixed64, double64-bit2string, bytes, embedded messages, packed repeated fieldsLength-delimited3groups (废弃)Start group4groups (废弃)End group5fixed32, sfixed32, float32-bit

“wire type” 中的 ”3“ 和 ”4“ 类型已废弃。这块不做讲解。

下来通过一个 message 信息展开说明。如下:

message HelloRequest {
  string name = 1;
  int32 num = 2;
  float height = 3;
  repeated int32 hobbies= 4;
}
复制代码

这就好比我上面所说的 ”结构“。发送方和接收方就是通过该结构去解析数据。现在我们就针对上面留下的问题一一说明。

1. 类型和顺序

那传输的数据中如何保存 ”数据类型“ 和 ”顺序“?

数据类型对应到 “wire type”。顺序对应到 ”field number“。假如 int32 num = 2 对应如下:

  • wire type:0。通过上面表格对应。
  • field number:2。字段后的唯一编码。

将这两个信息按照如下公式组装:

(field_number << 3) | wire_type
复制代码

带入得:

(2 << 3) | 0 
→ 16
复制代码

2. Varint

对于 num 字段保存的数据如何如何压缩?假如 num 存储的数据为 300。按照 4 字节存储如下:

00000000 00000000 00000001 00101100
复制代码

从结果可以看到。真实有效的数据只有 2 字节。为了压缩。面对不同的数据大小会占用不用的字节数。

那如何记录数据长度?我们可以再增加一个字节去记录真实数据所占用的实际字节数。对于 300 数据。增加一个字节记录长度。那下来和数据一块总共需要 3 个字节。那还有什么办法再减少字节数吗?

当然会有呀。不然我就说了一堆废话。咱继续。

请出 Varint 算法。过程如下:

  • 将数据以 7 位为一组进行分割;
  • 将组的顺序颠倒。即:将 ”高位 → 低位“ 规则。改为 ”低位 → 高位“;
  • 识别每一组。如果该组后还有数据。就在该组前增加一位 ”1”。否则增加 “0”。

将数据 300 带入该算法。过程如下:

300: 00000000 00000000 00000001 00101100
→ 7 位分割:0000 0000000 0000000 0000010 0101100
→ 颠倒顺序:0101100 0000010 0000000 0000
→ 组前加 1/0:10101100 00000010
→ 十进制:172 2
复制代码

按照这套算法下来。将数据压缩为 2 个字节存储。而接收方拿到字节数据后。只需要按照高位识别。如果为 0。说明之后没有数据了。

最终。对于 int32 num = 2 结构和数据 300。压缩后的结果为:

16 172 2
复制代码

3. Length-delimited

现在说说 string name = 1 。该类型对应的 “wire type” 为 2。”field number” 为 2。记录 “顺序” 和 “类型” 方式和上面讲的一样。

重点说说数据如何记录。相比 Varint 算法。该类型就简单多了。只需要使用 Varint 算法记录数据的字节长度。

假如。name 的值为 “miao”。最终结果为:

10 4 109 105 97 111
复制代码

解释:

  • 10:(2 << 3) | 2 。
  • 4:字符串长度。
  • 之后:按照 “UTF-8” 编码保存。

对于 message 嵌套、repeated (数组或切片)、字节数组。也是按照该算法得到。

例如。repeated int32 hobbies= 4 。假设 hobbies 数据为 [10, 20]。最终结果为:

34 2 10 20
复制代码

4. 浮点数

针对浮点类型。就更简单了。浮点数据使用固定字节保存。记录 “顺序” 和 “类型” 依然是上面讲的。

假如。float height = 3 。该类型对应的 “wire type” 为 5。数据假设为 52.1。最终结果为:

29 102 102 80 66
复制代码

解释:

  • 29:(3 << 3) | 5 。
  • 之后:使用固定字节数 4。

如果使用了双精度。那对应的 “wire type” 为 1。数据占用字节数为 8。

5. sint32/sint64

这两个类型不知道你在写 proto 文件时有没有用到。明白这个很重要。不然有时候数据就不能起被到压缩的作用。

上面讲到的 Varint 算法中。我们知道了以 7 位一组。再增加一位 “识别位” 来起到压缩数据的作用。但存在一个问题。倘若存在负数时。那这种压缩方式就失效了。

至于为啥?如何解决的?

我先说结果。如果写 proto 文件时。设置的数据类型为 sint32 或 sint64 时。将采用 ZigZag 算法进行数据压缩。

ZigZag 算法我就不重复讲解了。直接看上一篇。

小结

学完本篇我们知道了 Protobuf 怎么做到了压缩数据。简单说下。就是删除一些没用的信息。采用自描述的方式记录 “类型”、“顺序”、“数据”。

而对于类型。只记录了 “wire type”。该类型确定了数据的大概处理方式。

那说它就一定比 JSON、XML 好吗?也不是。

因为要采用 Protobuf 方式传输数据。发送方和接收方必须采用同一套结构规则。也可以说 “协议”。所以。如果想提高数据的阅读性。降低这种规则的配合。就可以使用 JSON、XML。

后面我会使用 Go 语言实现 Protobuf 序列化和反序列化的核心算法。只要这样我才觉得真的明白了该算法的真谛。

大家还在搜:

  • 数据结构必考代码
  • 请写出八种基本数据类型,字节数
  • 以下哪一种基本数据类型代表的是字节
  • 更多网络推广文章推荐

    以上就是由互联网推广工程师 网创网 整理编辑的,如果觉得有帮助欢迎收藏转发~

    分享到 :
    相关推荐

    发表评论

    您的电子邮箱地址不会被公开。

    评论(2)

    • 难入眠 永久VIP 2022年10月12日 22:55:43

      数据,字节,类型,算法,结构,代码,顺序,只需要,数据类型,信息

    • 明天的阳光美吗 永久VIP 2022年10月12日 22:55:43

      Protobuf 为啥比 JSON、XML 牛,现在知道了,不过这这篇解答确实也是太好了

    • 只求﹂份安宁 永久VIP 2022年10月12日 22:55:43

      今天。我带大家更深层次的认识认识 Protobuf。如果你对 Protobuf 的用法还不熟悉。直接前往:de