protobuf 的一些总结

发现好多团队在使用 protobuf , 以下简称pb, 去了解了下,写出来分享下,主要是从js开发者的角度说下我的理解。

什么是pb, 按google的官方文档说是有效的数据编码格式,谷歌在几乎所有的内部接口协议和文件格式都使用pb.

下面看个例子:

proto 定义文件,example.proto, 定义了Message对象:

   1:  message Message {
   2:      required string req = 1;
   3:      required Nest mynest = 4;
   4:      optional string opts = 2;
   5:      repeated string arr = 3;
   6:  
   7:      enum Corpus {
   8:          UNIVERSAL = 0;
   9:          WEB = 1;
  10:          IMAGES = 2;
  11:          LOCAL = 3;
  12:          NEWS = 4;
  13:          PRODUCTS = 5;
  14:          VIDEO = 6;
  15:        };
  16:  
  17:        optional Corpus corpus = 9 [default = WEB];
  18:  }
  19:  
  20:  
  21:  message Nest {
  22:    required string url = 1;
  23:    optional string title = 2;
  24:  }

操作proto的 example.js, 用pb 相对应的js 对象编码:

   1:  var builder = ProtoBuf.loadProtoFile( "testexample.proto“),
   2:      Message = builder.build("Message");
   3:  
   4:  var obj =
   5:  {
   6:      req  :  'i am required',
   7:      mynest : {
   8:          url : 'http://qq.com/'
   9:      },
  10:      opts : 'i am optional',
  11:      arr  : ['i am repeated', 'that is an array'],
  12:  }
  13:  
  14:  var msg = new Message(obj);
  15:  console.log(msg);

使用proto:

socket.send(msg.toBuffer());

例子使用了nodejs 的protobufjs, 大家可以使用,在安装之后可以看到有个example, 是个好的学习例子:

npm intall protopubjs

相信通过例子大家对pb有个初步的概念,下面从几点说下我了解的一些资料:

1. 编码特点

2. pb 和 js 对象的关系

编码

谷歌在设计时, 使得pb 编解码快,存储小,使得pb 容易被接受,主要来自下面的做法:

1.压缩每一个没有真正用到的字节,使之序列化后的字节尽量少

2 清晰的数据编码和诸多的位操作使之变得轻便简洁高效

首先pb使用了varint表示数字。

Varint 是一种紧凑的表示数字的方法。它用一个或多个字节来表示一个数字,值越小的数字使用越少的字节数,缺点是很大的值需要使用更多的字节。

下面看看pb 的编码

pb 编码使用key,value 的格式,从key 中可以解码出字段的数据格式,value 是存储的数据:

image007

从基本的数据格式入手了解下:

1. 数字:

05a311c042f3

例如:

proto 定义:

required uint32 req = 1;

传入值123,则该字段的存储如下:

第一个字节variant(1<<3|0),1 是field_num ,即上面proto中 “=” 之后的数字,  |0 中的0 是pb 中用0 表示uint32,

第二个字节variant(123)

2. 字符串

ee660f36413b

例如:

proto 定义:

required string req = 4;

传入值“hello”,则该字段的存储如下:

第一个字节variant(4<<3|2)  ,  4是field_number ,即上面proto中 “=” 之后的数字,   |2 中的 2 是pb 中用2 表示string

第二个字节用variant(5)表示”hello”的长度5 ,剩余的字节 “hello”

 

值得提重点提下的是 pb中使用field_number来索引字段 , 即用户指定的数字

1. 这么做是可以尽可能的缩小编码的存储,因为字符串的下标消耗的存储多些,并且数字下标基本用一个字节可以表示,当然需要变回原来的字段名, 需要使用原来的proto文件。

2. 这个字段的数字是由用户指定的, 并且在一个数据结构中数字不能重复,当然为了存储尽量的小, 使用的数值尽量的小。

 

protobuf 和js 对象之间的关系

从js 的角度理解pb 的数据合格:

pb js
message object
repeated array
optional 可以为null 的字段

 

参考资料:

benchmark:  https://code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking

编码格式:  https://developers.google.com/protocol-buffers/docs/encoding

Developer Guide:   https://developers.google.com/protocol-buffers/docs/overview

使用和原理: http://www.ibm.com/developerworks/cn/linux/l-cn-gpb/

protobuf编码详解:  http://www.cnblogs.com/cobbliu/archive/2013/03/02/2940074.html



Tags:

发表评论

电子邮件地址不会被公开。 必填项已用*标注