Protocol Buffers 序列化协议及应用

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

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,感兴趣的同学可以去下载研究一下。

替代文字

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • iOS

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

    89 引用 • 150 回帖 • 2 关注
  • golang

    Go 语言是 Google 推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发 Go,是因为过去 10 多年间软件开发的难度令人沮丧。Go 是谷歌 2009 发布的第二款编程语言。

    498 引用 • 1395 回帖 • 247 关注
  • 电影

    这是一个不能说的秘密。

    122 引用 • 608 回帖
  • PWL

    组织简介

    用爱发电 (Programming With Love) 是一个以开源精神为核心的民间开源爱好者技术组织,“用爱发电”象征开源与贡献精神,加入组织,代表你将遵守组织的“个人开源爱好者”的各项条款。申请加入:用爱发电组织邀请帖
    用爱发电组织官网:https://programmingwithlove.stackoverflow.wiki/

    用爱发电组织的核心驱动力:

    • 遵守开源守则,体现开源&贡献精神:以分享为目的,拒绝非法牟利。
    • 自我保护:使用适当的 License 保护自己的原创作品。
    • 尊重他人:不以各种理由、各种漏洞进行未经允许的抄袭、散播、洩露;以礼相待,尊重所有对社区做出贡献的开发者;通过他人的分享习得知识,要留下足迹,表示感谢。
    • 热爱编程、热爱学习:加入组织,热爱编程是首当其要的。我们欢迎热爱讨论、分享、提问的朋友,也同样欢迎默默成就的朋友。
    • 倾听:正确并恳切对待、处理问题与建议,及时修复开源项目的 Bug ,及时与反馈者沟通。不抬杠、不无视、不辱骂。
    • 平视:不诋毁、轻视、嘲讽其他开发者,主动提出建议、施以帮助,以和谐为本。只要他人肯努力,你也可能会被昔日小看的人所超越,所以请保持谦虚。
    • 乐观且活跃:你的努力决定了你的高度。不要放弃,多年后回头俯瞰,才会发现自己已经成就往日所仰望的水平。积极地将项目开源,帮助他人学习、改进,自己也会获得相应的提升、成就与成就感。
    1 引用 • 487 回帖 • 5 关注
  • OpenStack

    OpenStack 是一个云操作系统,通过数据中心可控制大型的计算、存储、网络等资源池。所有的管理通过前端界面管理员就可以完成,同样也可以通过 Web 接口让最终用户部署资源。

    10 引用 • 5 关注
  • V2EX

    V2EX 是创意工作者们的社区。这里目前汇聚了超过 400,000 名主要来自互联网行业、游戏行业和媒体行业的创意工作者。V2EX 希望能够成为创意工作者们的生活和事业的一部分。

    16 引用 • 236 回帖 • 264 关注
  • V2Ray
    1 引用 • 15 回帖
  • DNSPod

    DNSPod 建立于 2006 年 3 月份,是一款免费智能 DNS 产品。 DNSPod 可以为同时有电信、网通、教育网服务器的网站提供智能的解析,让电信用户访问电信的服务器,网通的用户访问网通的服务器,教育网的用户访问教育网的服务器,达到互联互通的效果。

    6 引用 • 26 回帖 • 529 关注
  • SEO

    发布对别人有帮助的原创内容是最好的 SEO 方式。

    35 引用 • 200 回帖 • 31 关注
  • JetBrains

    JetBrains 是一家捷克的软件开发公司,该公司位于捷克的布拉格,并在俄国的圣彼得堡及美国麻州波士顿都设有办公室,该公司最为人所熟知的产品是 Java 编程语言开发撰写时所用的集成开发环境:IntelliJ IDEA

    18 引用 • 54 回帖
  • ZeroNet

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

    1 引用 • 21 回帖 • 650 关注
  • Solidity

    Solidity 是一种智能合约高级语言,运行在 [以太坊] 虚拟机(EVM)之上。它的语法接近于 JavaScript,是一种面向对象的语言。

    3 引用 • 18 回帖 • 436 关注
  • 锤子科技

    锤子科技(Smartisan)成立于 2012 年 5 月,是一家制造移动互联网终端设备的公司,公司的使命是用完美主义的工匠精神,打造用户体验一流的数码消费类产品(智能手机为主),改善人们的生活质量。

    4 引用 • 31 回帖 • 4 关注
  • Google

    Google(Google Inc.,NASDAQ:GOOG)是一家美国上市公司(公有股份公司),于 1998 年 9 月 7 日以私有股份公司的形式创立,设计并管理一个互联网搜索引擎。Google 公司的总部称作“Googleplex”,它位于加利福尼亚山景城。Google 目前被公认为是全球规模最大的搜索引擎,它提供了简单易用的免费服务。不作恶(Don't be evil)是谷歌公司的一项非正式的公司口号。

    49 引用 • 192 回帖
  • PHP

    PHP(Hypertext Preprocessor)是一种开源脚本语言。语法吸收了 C 语言、 Java 和 Perl 的特点,主要适用于 Web 开发领域,据说是世界上最好的编程语言。

    180 引用 • 408 回帖 • 486 关注
  • 钉钉

    钉钉,专为中国企业打造的免费沟通协同多端平台, 阿里巴巴出品。

    15 引用 • 67 回帖 • 279 关注
  • Ubuntu

    Ubuntu(友帮拓、优般图、乌班图)是一个以桌面应用为主的 Linux 操作系统,其名称来自非洲南部祖鲁语或豪萨语的“ubuntu”一词,意思是“人性”、“我的存在是因为大家的存在”,是非洲传统的一种价值观,类似华人社会的“仁爱”思想。Ubuntu 的目标在于为一般用户提供一个最新的、同时又相当稳定的主要由自由软件构建而成的操作系统。

    127 引用 • 169 回帖
  • IPFS

    IPFS(InterPlanetary File System,星际文件系统)是永久的、去中心化保存和共享文件的方法,这是一种内容可寻址、版本化、点对点超媒体的分布式协议。请浏览 IPFS 入门笔记了解更多细节。

    21 引用 • 245 回帖 • 226 关注
  • GitBook

    GitBook 使您的团队可以轻松编写和维护高质量的文档。 分享知识,提高团队的工作效率,让用户满意。

    3 引用 • 8 回帖 • 1 关注
  • OpenShift

    红帽提供的 PaaS 云,支持多种编程语言,为开发人员提供了更为灵活的框架、存储选择。

    14 引用 • 20 回帖 • 657 关注
  • Webswing

    Webswing 是一个能将任何 Swing 应用通过纯 HTML5 运行在浏览器中的 Web 服务器,详细介绍请看 将 Java Swing 应用变成 Web 应用

    1 引用 • 15 回帖 • 640 关注
  • CAP

    CAP 指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可兼得。

    12 引用 • 5 回帖 • 632 关注
  • 数据库

    据说 99% 的性能瓶颈都在数据库。

    345 引用 • 745 回帖
  • 支付宝

    支付宝是全球领先的独立第三方支付平台,致力于为广大用户提供安全快速的电子支付/网上支付/安全支付/手机支付体验,及转账收款/水电煤缴费/信用卡还款/AA 收款等生活服务应用。

    29 引用 • 347 回帖 • 2 关注
  • WordPress

    WordPress 是一个使用 PHP 语言开发的博客平台,用户可以在支持 PHP 和 MySQL 数据库的服务器上架设自己的博客。也可以把 WordPress 当作一个内容管理系统(CMS)来使用。WordPress 是一个免费的开源项目,在 GNU 通用公共许可证(GPLv2)下授权发布。

    66 引用 • 114 回帖 • 190 关注
  • 小薇

    小薇是一个用 Java 写的 QQ 聊天机器人 Web 服务,可以用于社群互动。

    由于 Smart QQ 从 2019 年 1 月 1 日起停止服务,所以该项目也已经停止维护了!

    35 引用 • 468 回帖 • 762 关注
  • 尊园地产

    昆明尊园房地产经纪有限公司,即:Kunming Zunyuan Property Agency Company Limited(简称“尊园地产”)于 2007 年 6 月开始筹备,2007 年 8 月 18 日正式成立,注册资本 200 万元,公司性质为股份经纪有限公司,主营业务为:代租、代售、代办产权过户、办理银行按揭、担保、抵押、评估等。

    1 引用 • 22 回帖 • 788 关注