Protocol Buffers 序列化协议及应用

本贴最后更新于 1921 天前,其中的信息可能已经事过景迁

Protocol Buffers 是 Google 开发一种数据描述语言,能够将结构化数据序列化,可用于数据存储、通信协议等方面。据 Google 官方文档介绍,现在 Google 内部已经有 48,162 个消息类型定义在 12,183 个 proto 文件中。本文会从快速入门、语言规范、编码协议、性能评估等几个方面对 Prototol Buffers 进行介绍。

替代文字

不了解 Protocol Buffers 的同学可以把它理解为更快、更简单、更小的 JSON 或者 XML,区别在于 Protocol Buffers 是二进制格式,而 JSON 和 XML 是文本格式。

替代文字

相对于 XML,Protocol Buffers 的具有如下几个优点:

  • 简洁
  • 体积小:消息大小只需要 XML 的 1/10 ~ 1/3
  • 速度快:解析速度比 XML 快 20 ~ 100 倍
  • 使用 Protocol Buffers 的编译器,可以生成更容易在编程中使用的数据访问代码
  • 更好的兼容性,Protocol Buffers 设计的一个原则就是要能够很好的支持向下或向上兼容。

替代文字

看一个简单的对比例子,表达一个用户的三个基本的属性,如果使用 XML 消息体大小为 82 bytes。

替代文字

如果使用 JSON 消息体大小为 56 bytes。

替代文字

使用 Protocol Buffers 咋则只需要 31 bytes,看到这些二进制数据大家可以暂时忽略,后面会具体分析这些二进制数据是如何编码的。

替代文字

接下来先看一个简单的入门示例,在该例子中我们从准备环境开始,编写 proto 文件,到最后使用 Protocol Buffers 编译器生成代码,再到具体的使用。

替代文字

https://github.com/google/protobuf 下载编译安装 protoc,并下载 ProtobufSDK。

替代文字

开始编写 proto 文件,使用 message 关键字定义消息类型,消息中每个字段需要指定字段类型和字段序号。同一个 message 中字段

替代文字

使用 protoc 命令生成代码,使用--cpp_out、--java_out、--python_out 命令选项可以生成 C++、Java、Python 代码,在最新版本 Protocol Buffers v3 中还加入了 ruby 语言的支持。

替代文字

生成代码的代码可以直接加入到自己的代码工程中使用,以 C++ 语言为例:

替代文字

这是一段 Java 语言的使用示例:

替代文字

接下来会详细说明如何定义 proto 文件:

替代文字

在消息定义中,我们需要确定三个问题:

  • 确定消息命名,给消息取一个有意义的名字。

  • 指定字段的类型

  • 定义字段的编号,在 Protocol Buffers 中,字段的编号非常重要,字段名仅仅是作为参考和生成代码用。需要注意的是字段的编号区间范围,其中 19000 ~ 19999 被 Protocol Buffers 作为保留字段。

    替代文字

    字段约束,required 指定该字段必须赋值,禁止为空(在 v3 中该约束被移除);optional 指定字段为可选字段,可以为空,对于 optional 字段还可以使用[default]指定默认值,如果没有指定,则会使用字段类型的默认值;使用 repeated 指定字段为集合。

    替代文字

    在一个 proto 文件中可以同时定义多个 message 类型,生成代码时根据生成代码的目标语言不同,处理的方式不太一样,如 Java 会针对每个 message 类型生成一个.java 文件。还可以使用 C++ 风格的注释。

    替代文字

    在 Protocol Buffers 中提供了很多的标量类型,供我们在定义字段类型时使用。

    替代文字

    可以指定字段的类型为其他 message 类型,如图中的示例代码所示:

    替代文字

    还可以使用 import 关键字导入其他 proto 文件,这有利于你进行自己的 proto 文件的规划和整理。

    替代文字

    在 proto 文件中消息的类型还可以嵌套,如你定义的 message 类型仅作为另外一个 Message 的字段类型。

    替代文字

    为了便于扩展,在 proto 文件中可以使用 extensions 关键字预留一部分字段编号出来,以便于后期给第三方扩展时使用。

    替代文字

    oneof 关键字指定一组字段中,至少要有一个字段必须赋值。如在用户登录系统中,使用邮箱和用户名都可以登录该系统,所以通常会要求至少提供用户名或者邮箱。

    替代文字

    在这一部分总我们会仔细分析,Protocol Buffers 序列化后的二进制代码的编码协议,不知道这些并不会影响我们使用 Protocol Buffers,但是了解之后有助于我们更好的使用 Protocol Buffers 和进行调试。

    替代文字

    先从一个简单的例子开始,如图中的代码所示,我们有这样一个消息定义,在使用中给 a 赋值为 150,最终编码得到的结果是 08 96 01,为什么编码的结果是这样,其中 08 又代表什么?后续一一为你介绍。

    替代文字

    在 Protocol Buffers 中采用 Base-128 变长编码,所谓变长编码是和定长编码相对的,定长编码使用固定字节数来表示,如 int32 类型的数字固定使用 4 bytes 表示,而变长编码是需要几个字节就使用几个字节,如对于 int32 类型的数字 1 来说,只需要 1 bytes 足够。Base-128 变长编码的原则就两条:

  • 每个字节使用使用低 7 位表示数字,除了最后一个字节,其他字节的最高位都设置为 1。

  • 采用 Little-Endian 字节序

替代文字

一个 Protocol Buffers 的消息包含一系列字段 key/value,每个字段由一个变长 32 位整数作为字段头,后面跟随字段体。字段头的格式如下:

(field_number << 3) | wire_type

-field_number:    字段序号 
-wire_type:    字段编码类型 

替代文字

这里是详细的字段说明,其中 3、4 已经放弃:

替代文字

替代文字

替代文字

替代文字

替代文字

替代文字

接下来我们对 Protocol Buffers 的性能做一些测试。

替代文字

在测试过程中,我们使用一个统一的消息体格式,主要评估以下两个性能指标:

  • 序列化速度
  • 报文大小

替代文字

替代文字

替代文字

替代文字

替代文字

尽管 Protocol Buffers 有序列化速度快、报文体积小以及更好的兼容性等优点,但同时也有一些缺点,在使用时要根据实际情况来选择使用。

  • 缺乏自描述,可读性差,可以使用 TextFormat
  • 适用于内部服务和存储,而不适合直接对外公开,如 Open API,protobuf v3 将加入对 json 的支持,可解决此问题

替代文字

与 Protocol Buffers 类似的框架有微软出的 Bond 和 Facebook 出的 Thrift,感兴趣的同学可以去下载研究一下。

替代文字

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • Sym

    Sym 是一款用 Java 实现的现代化社区(论坛/BBS/社交网络/博客)系统平台。

    下一代的社区系统,为未来而构建

    524 引用 • 4599 回帖 • 701 关注
  • SendCloud

    SendCloud 由搜狐武汉研发中心孵化的项目,是致力于为开发者提供高质量的触发邮件服务的云端邮件发送平台,为开发者提供便利的 API 接口来调用服务,让邮件准确迅速到达用户收件箱并获得强大的追踪数据。

    2 引用 • 8 回帖 • 446 关注
  • CSS

    CSS(Cascading Style Sheet)“层叠样式表”是用于控制网页样式并允许将样式信息与网页内容分离的一种标记性语言。

    186 引用 • 471 回帖 • 2 关注
  • 快应用

    快应用 是基于手机硬件平台的新型应用形态;标准是由主流手机厂商组成的快应用联盟联合制定;快应用标准的诞生将在研发接口、能力接入、开发者服务等层面建设标准平台;以平台化的生态模式对个人开发者和企业开发者全品类开放。

    15 引用 • 127 回帖 • 1 关注
  • 阿里云

    阿里云是阿里巴巴集团旗下公司,是全球领先的云计算及人工智能科技公司。提供云服务器、云数据库、云安全等云计算服务,以及大数据、人工智能服务、精准定制基于场景的行业解决方案。

    89 引用 • 345 回帖 • 1 关注
  • 书籍

    宋真宗赵恒曾经说过:“书中自有黄金屋,书中自有颜如玉。”

    76 引用 • 390 回帖 • 1 关注
  • 开源

    Open Source, Open Mind, Open Sight, Open Future!

    402 引用 • 3521 回帖 • 1 关注
  • CentOS

    CentOS(Community Enterprise Operating System)是 Linux 发行版之一,它是来自于 Red Hat Enterprise Linux 依照开放源代码规定释出的源代码所编译而成。由于出自同样的源代码,因此有些要求高度稳定的服务器以 CentOS 替代商业版的 Red Hat Enterprise Linux 使用。两者的不同在于 CentOS 并不包含封闭源代码软件。

    238 引用 • 224 回帖
  • API

    应用程序编程接口(Application Programming Interface)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。

    76 引用 • 429 回帖
  • WiFiDog

    WiFiDog 是一套开源的无线热点认证管理工具,主要功能包括:位置相关的内容递送;用户认证和授权;集中式网络监控。

    1 引用 • 7 回帖 • 561 关注
  • V2Ray
    1 引用 • 15 回帖 • 2 关注
  • RIP

    愿逝者安息!

    8 引用 • 92 回帖 • 321 关注
  • LeetCode

    LeetCode(力扣)是一个全球极客挚爱的高质量技术成长平台,想要学习和提升专业能力从这里开始,充足技术干货等你来啃,轻松拿下 Dream Offer!

    209 引用 • 72 回帖
  • ZeroNet

    ZeroNet 是一个基于比特币加密技术和 BT 网络技术的去中心化的、开放开源的网络和交流系统。

    1 引用 • 21 回帖 • 609 关注
  • CSDN

    CSDN (Chinese Software Developer Network) 创立于 1999 年,是中国的 IT 社区和服务平台,为中国的软件开发者和 IT 从业者提供知识传播、职业发展、软件开发等全生命周期服务,满足他们在职业发展中学习及共享知识和信息、建立职业发展社交圈、通过软件开发实现技术商业化等刚性需求。

    14 引用 • 155 回帖
  • iOS

    iOS 是由苹果公司开发的移动操作系统,最早于 2007 年 1 月 9 日的 Macworld 大会上公布这个系统,最初是设计给 iPhone 使用的,后来陆续套用到 iPod touch、iPad 以及 Apple TV 等产品上。iOS 与苹果的 Mac OS X 操作系统一样,属于类 Unix 的商业操作系统。

    84 引用 • 139 回帖 • 1 关注
  • 互联网

    互联网(Internet),又称网际网络,或音译因特网、英特网。互联网始于 1969 年美国的阿帕网,是网络与网络之间所串连成的庞大网络,这些网络以一组通用的协议相连,形成逻辑上的单一巨大国际网络。

    96 引用 • 330 回帖
  • Netty

    Netty 是一个基于 NIO 的客户端-服务器编程框架,使用 Netty 可以让你快速、简单地开发出一个可维护、高性能的网络应用,例如实现了某种协议的客户、服务端应用。

    49 引用 • 33 回帖 • 20 关注
  • TextBundle

    TextBundle 文件格式旨在应用程序之间交换 Markdown 或 Fountain 之类的纯文本文件时,提供更无缝的用户体验。

    1 引用 • 2 回帖 • 40 关注
  • Wide

    Wide 是一款基于 Web 的 Go 语言 IDE。通过浏览器就可以进行 Go 开发,并有代码自动完成、查看表达式、编译反馈、Lint、实时结果输出等功能。

    欢迎访问我们运维的实例: https://wide.b3log.org

    30 引用 • 218 回帖 • 615 关注
  • Spark

    Spark 是 UC Berkeley AMP lab 所开源的类 Hadoop MapReduce 的通用并行框架。Spark 拥有 Hadoop MapReduce 所具有的优点;但不同于 MapReduce 的是 Job 中间输出结果可以保存在内存中,从而不再需要读写 HDFS,因此 Spark 能更好地适用于数据挖掘与机器学习等需要迭代的 MapReduce 的算法。

    74 引用 • 46 回帖 • 555 关注
  • 安装

    你若安好,便是晴天。

    131 引用 • 1184 回帖
  • HTML

    HTML5 是 HTML 下一个的主要修订版本,现在仍处于发展阶段。广义论及 HTML5 时,实际指的是包括 HTML、CSS 和 JavaScript 在内的一套技术组合。

    103 引用 • 294 回帖 • 1 关注
  • SSL

    SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS 与 SSL 在传输层对网络连接进行加密。

    69 引用 • 190 回帖 • 474 关注
  • Markdown

    Markdown 是一种轻量级标记语言,用户可使用纯文本编辑器来排版文档,最终通过 Markdown 引擎将文档转换为所需格式(比如 HTML、PDF 等)。

    165 引用 • 1474 回帖
  • GitLab

    GitLab 是利用 Ruby 一个开源的版本管理系统,实现一个自托管的 Git 项目仓库,可通过 Web 界面操作公开或私有项目。

    46 引用 • 72 回帖
  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    20156 引用 • 77717 回帖