开源点评:Protocol Buffers介绍

  今天来介绍一下“Protocol Buffers”(下面简称protobuf)这个玩意儿。本来俺在构思“生产者/消费者模式

”系列的下一个帖子:关于生产者和消费者之间的传输数据格式。因为里面扯到了protobuf,想想干脆单独开一个帖子算了。

  ★protobuf是啥玩意儿?

  为了照应从没听说过的同学,照例先来扫盲一把。

  首先,protobuf是一个开源项目(官方网站在“这里

”),并且是后台非常硬的开源项目。网上现有的大部分(至少80%)开源项目,要么是某人单干、要么是几个闲杂人等合伙搞。而protobuf则不然,它是鼎鼎大名的Google公司开发出来,并且在Google内部久经考验的一个东东。由此可见,它的作者绝非一般闲杂人等可比。

  那这个听起来牛X的东东究竟有啥用处捏?简单地说,这个东东干的事儿事实上和XML差点儿相同,也就是把某种数据结构的信息,以某种格式保存起来。主要用于数据存储、传输协议格式等
场合。有同学可能心理犯嘀咕了:放着好好的XML不用,干嘛又一次发明轮子啊?!先别急,后面俺自然会有说道。

  话说到了去年(大约是08年7
月),Google突然大发慈悲,把这个好东西贡献给了开源社区。这下,像俺这样的喜欢捡现成的家伙可就有福啦!貌似喜欢捡现成的家伙还蛮多滴,再加上Google的号召力,开源后不到一年,protobuf的人气就已经非常旺了。所以俺为了与时俱进,就单独开个帖子来忽悠一把。

  ★protobuf有啥特色?

  扫盲完了之后,就该聊一下技术方面的话题了。因为这玩意儿公布的时间较短(未满周岁),所以俺接触的时间也不长。今天在此是先学现卖,列位看官多多包涵 :-)

  ◇性能好/效率高

  如今,俺就来说说Google公司为啥放着好端端的XML不用,非要另起炉灶,又一次造轮子。一个根本的原因是XML性能不够好。

  先说时间开销:XML格式化(序列化)的开销倒还好;可是XML解析(反序列化)的开销就不敢恭维啦。俺之前常常碰到一些时间性能非常敏感的场合,因为不堪忍受XML解析的速度,弃之如敝履。

  再来看空间开销:熟悉XML语法的同学应该知道,XML格式为了有较好的可读性,引入了一些冗余的文本信息。所以空间开销也不是太好(只是这点缺点,俺不常碰到)。

 
 因为Google公司赖以吹嘘的就是它的海量数据和海量处理能力。对于几十万、上百万机器的集群,动不动就是PB级的数据量,哪怕性能略微提高0.1%也是相当可观滴。所以Google自然无法容忍XML在性能上的明显缺点。再加上Google从来就不缺造轮子的牛人,所以protobuf也就应运而生了。

  Google对于性能的偏执,那但是出了名的。所以,俺对于Google搞出来protobuf是很滴放心,性能上不敢说是最好,但肯定不会太差。

  ◇代码生成机制

  除了性能好,代码生成机制是主要吸引俺的地方。为了说明这个代码生成机制,俺举个样例。

  比方有个电子商务的系统(如果用C++实现),当中的模块A须要发送大量的订单信息给模块B,通讯的方式使用socket。

如果订单包含例如以下属性:

--------------------------------

  时间:time(用整数表示)

  客户id:userid(用整数表示)

  交易金额:price(用浮点数表示)

  交易的描写叙述:desc(用字符串表示)

--------------------------------

  假设使用protobuf实现,首先要写一个proto文件(最好还是叫Order.proto),在该文件里加入一个名为"Order"的message结构,用来描写叙述通讯协议中的结构化数据。该文件的内容大致例如以下:

--------------------------------

message Order

{
 
required int32 time = 1;
 
required int32 userid = 2;
 
required float price = 3;
 
optional string desc = 4;

}

--------------------------------

  然后,使用protobuf内置的编译器编译

该proto。因为本样例的模块是C++,你能够通过protobuf编译器的命令行參数(看“这里

”),指定它生成C++语言的“订单包装类”。(一般来说,一个message结构会生成一个包装类)

  然后你使用相似以下的代码来序列化/解析该订单包装类:

--------------------------------

// 发送方

Order order;

order.set_time(XXXX);

order.set_userid(123);

order.set_price(100.0f);

order.set_desc("a test order");

string sOrder;

order.SerailzeToString(&sOrder);

// 然后调用某种socket的通讯库把序列化之后的字符串发送出去

// ......

--------------------------------

// 接收方

string sOrder;

// 先通过网络通讯库接收到数据,存放到某字符串sOrder

// ......

Order order;

if(order.ParseFromString(sOrder)) // 解析该字符串

{
 
cout << "userid:" << order.userid() << endl
  << "desc:" << order.desc() << endl;

}

else

{
 
cerr << "parse error!" << endl;

}

--------------------------------

  有了这样的代码生成机制,开发者再也不用吭哧吭哧地编写那些协议解析的代码了(干这样的活是典型的吃力不讨好)。

  万一将来需求发生变更,要求给订单再添加一个“状态”的属性,那仅仅须要在Order.proto文件里添加一行代码。对于发送方(模块A),仅仅要添加一行设置状态的代码;对于接收方(模块B)仅仅要添加一行读取状态的代码。哇塞,简直太轻松了!

  另外,假设通讯两方使用不同的编程语言来实现,使用这样的机制能够有效确保两边的模块对于协议的处理是一致的。

  顺便跑题一下。

  从某种意义上讲,能够把proto文件看成是描写叙述通讯协议的规格说明书(或者叫接口规范)。这样的伎俩事实上老早就有了,搞过微软的COM编程或者接触过CORBA的同学,应该都能从中看到IDL(详解看“这里

”)的影子。它们的思想是相通滴。

  ◇支持“向后兼容”和“向前兼容”

  还是拿刚才的样例来说事儿。为了叙述方便,俺把添加了“状态”属性的订单协议成为“新版本号”;之前的叫“老版本号”。

  所谓的“向后兼容”(backward compatible),就是说,当模块B升级了之后,它可以正确识别模块A发出的老版本号的协议。因为老版本号没有“状态”这个属性,在扩充协议时,可以考虑把“状态”属性设置成非必填

的,或者给“状态”属性设置一个缺省值(怎样设置缺省值,參见“这里

”)。

  所谓的“向前兼容”(forward compatible),就是说,当模块A升级了之后,模块B可以正常识别模块A发出的新版本号的协议。这时候,新添加的“状态”属性会被忽略。

  “向后兼容”和“向前兼容”有啥用捏?俺举个样例:当你维护一个非常庞大的分布式系统时,因为你无法同一时候
升级全部
模块,为了保证在升级过程中,整个系统可以尽可能不受影响,就须要尽量保证通讯协议的“向后兼容”或“向前兼容”。

  ◇支持多种编程语言

  俺开博以来点评的几个开源项目(比方“Sqlite

”、“cURL

”),都是支持非常多种

编程语言滴,这次的protobuf也不例外。在Google官方公布的源码中包括了C++、Java、Python三种语言(正好也是俺最经常使用的三种,真爽)。假设你平时用的就是这三种语言之中的一个,那就好办了。

  假如你想把protobuf用于其他语言,咋办捏?因为Google一呼百应的号召力,开源社区对protobuf响应踊跃,最近冒出非常多其他编程语言
的版本号(比方ActionScript、C#、Lisp、Erlang、Perl、PHP、Ruby等),有些语言还同一时候搞出了多个开源的项目。详细细节能够參见“这里

”。

  只是俺有义务提醒一下在座的各位同学。假设你考虑把protobuf用于上述这些语言,一定认真评估相应的开源库。由于这些开源库不是Google官方提供的、并且出来的时间还不长。所以,它们的质量、性能等方面可能还有欠缺。

  ★protobuf有啥缺陷?

  前几天刚刚在“光环效应

”的帖子里强调了“要同一时候评估长处和缺点”。所以俺最后再来批判一下这玩意儿的缺点。

  ◇应用不够广

  因为protobuf刚发布没多久,相比XML而言,protobuf还属于初出茅庐。因此,在知名度、应用广度等方面都远不如XML。因为这个原因,假如你设计的系统须要提供若干对外的接口给第三方系统调用,俺奉劝你临时不要考虑protobuf格式。

  ◇二进制格式导致可读性差

  为了提高性能,protobuf採用了二进制格式进行编码。这直接导致了可读性差的问题(严格地说,是没有可读性)。尽管protobuf提供了TextFormat这个工具类(文档在“这里

”),但终究无法彻底解决此问题。

 
 可读性差的危害,俺再来举个样例。比方通讯两方假设出现故障,极易导致扯皮(都不承认自己有问题,都说是对方的错)。俺对付扯皮的一个简单方法就是直接抓包并dump成log,能比較easy地看出错误在哪一方。可是protobuf的二进制格式,导致你抓包并直接dump出来的log难以看懂。

  ◇缺乏自描写叙述

  一般来说,XML是自描写叙述的,而protobuf格式则不是。给你一段二进制格式的协议内容,假设不配合对应的proto文件,那简直就像天书一般。

  因为“缺乏自描写叙述”,再加上“二进制格式导致可读性差”。所以在配置文件方面,protobuf是肯定无法代替XML的地位滴。

  ★为什么俺会用上protobuf?

  俺自从前段时间接触了protobuf之后,就着手把俺负责的产品中的部分

传输数据协议替换成protobuf。可能有同学会问,和protobuf相似的东东也有不少,为啥独独相中protobuf捏?因为今天写的篇幅已经蛮长了,俺卖个关子,把这个话题留到“生产者/消费者模式[5]:怎样选择传输协议及格式?”。俺会在兴许的这个帖子里对照各种五花八门的协议格式,并谈谈俺的浅见。



版权声明

本博客全部的原创文章,作者皆保留版权。转载必须包括本声明,保持本文完整,并以超链接形式注明作者编程随想
和本文原始地址:

http://program-think.blogspot.com/2009/05/opensource-review-protocol-buffers.html

开源点评:Protocol Buffers介绍

时间: 2024-11-02 23:51:00

开源点评:Protocol Buffers介绍的相关文章

Protocol buffers 介绍

Protocol buffers和mxl一样在序列化数据结构时很灵活.高效和智能,但是它的优势在于定义文件更小,读取速度更快,使用更加简单.目前protocol buffers支持C++.java和python三种语言并且独立于平台. linux环境安装 下载protobuf-2.5.0.tar.gz tar -xvf protobuf-2.5.0.tar.gz ./configure --prefix=/usr/local/protobuf-2.5.0 make make install 安装

(转)Protocol Buffers for C

我一直不太满意 google protocol buffers 的默认设计.为每个 message type 生成一大坨 C++ 代码让我很难受.而且官方没有提供 C 版本,第三方的 C 版本 也不让我满意. 这种设计很难让人做动态语言的 binding ,而大多数动态语言往往又没有强类型检查,采用生成代码的方式并没有特别的好处,反而有很大的性能损失(和通常做一个 bingding 库的方式比较).比如官方的 Python 库,完全可以在运行时,根据协议,把那些函数生成出来,而不必用离线的工具生

从Protocol Buffers 到 gRPC

从Protocol Buffers 到 gRPC 我们项目中准备使用Protocol Buffers来进行服务器和客户端的消息交互,采用gRPC开源框架,服务器使用Java,客户端有Android和iOS. 从Protocol Buffers 到 gRPC 一Protocol Buffers 文档 使用 1 定义一个消息类型 官方例子 2 字段限制 3 Tags 4 具体使用 Protoc源码的编译以及使用 1 安装ProtocolBuffer工具 2 使用protoc编译proto文件 二gR

Protocol Buffers(Protobuf)开发者指南---概览

Protocol Buffers(Protobuf)开发者指南---概览 欢迎来到protocol buffers的开发者指南文档,protocol buffers是一个与编程语言无关‘.系统平台无关.可扩展的结构化数据序列化/反序列化工具,适用于通讯协议,数据存储等场合. ps:为了方便拼写,下文的protobuf就是指protocol buffers. 本文档的面向读者是:希望使用protobuf的 Java.C++.Python的开发者.此概览将向您介绍如何开始使用protobuf,然后您

Java使用Protocol Buffers入门四步骤

Protocol Buffers(简称protobuf)是谷歌的一项技术,用于将结构化的数据序列化.反序列化,经常用于网络传输. 这货实际上类似于XML生成和解析,但protobuf的效率高于XML,不过protobuf生成的是字节码,可读性比XML差.类似的还有json.Java的Serializable等. protobuf支持各种语言.本文以Java为例,简单介绍protobuf如何使用.其他语言使用方法类似. 首先需要下载: http://download.csdn.net/downlo

protocol buffer介绍(protobuf)

一.理论概述0.参考资料入门资料:https://developers.google.com/protocol-buffers/docs/javatutorial更详细的资料:For more detailed reference information, see the Protocol Buffer Language Guide, the Java API Reference, the Java Generated Code Guide, and the Encoding Reference

Protocol Buffers(Protobuf) 官方文档--Protobuf语言指南

Protocol Buffers(Protobuf) 官方文档--Protobuf语言指南 约定:为方便书写,ProtocolBuffers在下文中将已Protobuf代替. 本指南将向您描述如何使用protobuf定义i结构化Protobuf数据,包括.proto文件语法和如何使用.proto文件生成数据存取类. 作为一个参考指南,本文档将以示例的形式一步步向您介绍Protobuf的特点.您可以参考您所选择的语言的示例.tutorial ----------------------------

FlatBuffers vs Protocol Buffers

FlatBuffers去年发布,最近看了一下,与同是出自Google之手的Protocol Buffers非常类似.在官网上介绍,FlatBuffers(简称FB)主要针对game development和对性能有要求的应用.相对于Protocol Buffers(简称PB),FB不需要解析,只通过序列化后的二进制buffer即可完成数据访问. FB的主要特点有: 1)数据访问不需要解析 将数据序列化成二进制buffer,之后的数据访问直接读取这个buffer,所以读取的效率很高. 2)内存高效

Protocol Buffers(protobuf)java初体验

由于项目需要所以简单的研究了下protobuf.我也是参照网上的博客,所以大部分内容我也就不重复造轮子了.首先protobuf介绍点击这里,使用介绍点击这里,使用demo看这里.我个人的第一个例子也是参照这个demo来的,不过其中我有遇到一些问题,所以揪出来说说,也就给自己做个笔记,方便查阅. 基本的东西相信大家也了解了,直接步入主题了: 1.限定修饰符介绍 required\optional\repeated,之前给定的博客已经有这个介绍了我也不多说,这里把一些小玩儿拿出来讲讲 ①.requi