A Brief View of
Google Protocol Buffers

         刘海波
       bjhbliu@corp.netease.com



                                  1
内容大纲

简介
示例
.proto语法
.proto语法
数据编码
测试对比
实际应用
Q&A




             2
简介
GPB google开源的一种用于序列化结构化数据的协议。
    google开源的一种用于序列化结构化数据的协议。
   language-neutral, platform-neutral,
   extensible way of serializing structured
   data
   适用于数据存储、传输
使用IDL语言描述数据格式能够,然会对描述的数据进行二
使用IDL
    IDL语言描述数据格式能够,然会对描述的数据进行二
进制编码。PB类似XML,但是更快(速度: XML DOM文档
进制编码。PB 类似XML ,但是更快(速度:XML DOM文档
         PB类似 XML,但是更快(速度:
树)、更小(生成的二进制数据)、更简单(编码、 proto
树)、更小(生成的二进制数据)、更简单(编码、proto
vs schema)。下图是官网的数据( XML DOM访问):
   schema)。下图是官网的数据(
         )。下图是官网的数据(XML DOM访问):




编码复杂度对比参考 《Coding in GPB vs XML.doc》
编码复杂度对比参考《                  XML.doc》
                                              3
示例
安装环境,参考《Linux 下安装Google Protocol
安装环境,参考《
       ,参考《Linux 下安装Google
Buffers.doc》
Buffers.doc》
.proto编写
.proto编写
编译生成目标类:
    命令行:protoc -I=$SRC_DIR –java_out=$DST_DIR
    命令行:protoc
    $SRC_DIR/addressbook.proto 注:-I指定.proto文件所
                               注:-I 指定.proto
                                 -I指定 .proto文件所
    在目录 –java_out 指定生成java文件所在的目录
            java_out指定生成 java文件所在的目录
                    指定生成java
    eclipse:protoclipse 插件
    eclipse: protoclipse插件

代码:
pbdemotestaddress :
pbdemotestaddress:
      ListPeople.java 、 AddPerson.java
      ListPeople.java、
pbdemotestcomexampletutorialAddressBookProtos.java
pbdemotestdemoprotoaddressbook.proto




                                                          4
示例
                 解析AddressBookProtos.java
                 解析AddressBookProtos.java
编译生成目标类:
  命令行:protoc -I=$SRC_DIR –java_out=$DST_DIR
  命令行:protoc
  $SRC_DIR/addressbook.proto 注:-I指定.proto文件所在目录
                             注:-I 指定.proto
                               -I指定.proto文件所在目录
   java_out指定生成java文件所在的目录
  –java_out指定生成java文件所在的目录
           指定生成java
  eclipse:protoclipse插件
  eclipse:protoclipse插件

代码:
pbdemotestaddress :
pbdemotestaddress:
      ListPeople.java 、 AddPerson.java
      ListPeople.java、
pbdemotestcomexampletutorialAddressBookProtos.java
pbdemotestdemoprotoaddressbook.proto

java文件中的类结构:
java文件中的类结构:
class AddressBookProtos{
    class Person{
        class PhoneNumber{class Builder{} }
              PhoneNumber{class
        class Builder{}
    }
    class AddressBook{class Builder{} }
          AddressBook{class
}

                                                          5
示例
                    序列化/反序列化分析
所有的实体类都没有 setter方法,只有getter方法,相应的builder类中有setter方法
所有的实体类都没有setter方法,只有getter方法,相应的builder类中有setter
          setter方法,只有 getter方法,相应的 builder类中有 setter方法




通过查看代码可以看到,以上三个类的成员变量都是private类型的,而
通过查看代码可以看到,以上三个类的成员变量都是private类型的,而
   查看代码可以看到,以上三个类的成员变量都是private类型的,
且只提供getter方法,而没有提供setter方法去为数据变量赋值。
  只提供getter方法,而没有提供setter
     getter方法,而没有提供setter方法去为数据变量赋值。
PB利用了内部类可以访问到外部类中私有成员变量的特性。对外部类的任
PB利用了内部类可以访问到外部类中私有成员变量的特性。对外部类的任
何赋值操作都需要通过Builder内部类来进行。当调用Builder的build()
何赋值操作都需要通过Builder内部类来进行。当调用Builder
              Builder内部类来进行。  Builder的
方法时,会在方法体内创建一个指向外部类的引用(名为result),当赋
方法时,会在方法体内创建一个指向外部类的引用(名为result
     会在方法体内创建一个指向外部类的引用(名为result),当赋
值完成,会把这个对象返回。
PB通过这样一种方式保证了数据安全性,一旦数据构建完毕,将无法再对
PB通过这样一种方式保证了数据安全性,一旦数据构建完毕,将无法再对
其进行修改。                                                   6
示例
                    序列化/反序列化分析

一句话就可以实现反序列化:AddressBook addressBook =
AddressBook.parseFrom(new FileInputStream(filePath);
PB在parseFrom 后面做的事情:
PB在parseFrom后面做的事情:
   根据inputStream或者buffer去构造一个CodedInputStream;
   根据inputStream或者buffer去构造一个CodedInputStream
      inputStream或者buffer去构造一个CodedInputStream;
   然后使用生成代码中的mergeFrom方法,去解析二进制数据:
   然后使用生成代码中的mergeFrom
                    mergeFrom方法,去解析二进制数据:
    - 首先调用CodedInputStream的readTag,也就是从中取得key值
      首先调用CodedInputStream readTag,也就是从中取得key值
             CodedInputStream的     ,也就是从中取得key
      (int类型),然后根据tag找到field
        int类型),然后根据tag找到
           类型),然后根据tag找到field
    - 然后通过swtich块来往对象中赋值(PB采用了Base 128
      然后通过swtich块来往对象中赋值(PB采用了Base
             swtich块来往对象中赋值(PB采用了
      Varints的方式来编码这个数字)。
      Varints的方式来编码这个数字)。
   将数据解析完成后,会调用build()方法,将构建好的对象返回。
   将数据解析完成后,会调用build()  build()方法,将构建好的对象返回。
   注:在这个过程中要通过PB提供的Descriptor类还获取每个字段的
   注:在这个过程中要通过PB提供的Descriptor
                      PB提供的Descriptor类还获取每个字段的
   描述信息。




                                                       7
.proto文件语法
http://code.google.com/apis/protocolbuffers/do
cs/proto.html
java类是编译器根据proto文件生成的。作为一个IDL语言,
java类是编译器根据 proto文件生成的。作为一个 IDL语言,
    类是编译器根据proto 文件生成的。作为一个IDL
proto有相应的语法。
proto有相应的语法。
1、package:proto文件以一个package声明开始。这个声明是
   package: proto文件以一个 package声明开始。这个声明是
                 文件以一个package
为了防止不同项目之间的命名冲突。(proto文件的import)
为了防止不同项目之间的命名冲突。(proto 文件的import
                            proto文件的 import)
2、java_package
3、java_outer_classname :定义所有message类的容器类。
   java_outer_classname:定义所有 message类的容器类。
                       :定义所有message
4、message:一组类型字段的集合。同时被message修饰过的字
   message:一组类型字段的集合。同时被 message修饰过的字
          :一组类型字段的集合。同时被message
段,也可以当做类型,用于Nested message 声明中。
段,也可以当做类型,用于Nested message声明中。
  常用类型:WireType.doc
  常用类型:WireType.doc
  字段修饰:required、optional、repeated
  字段修饰:required optional、
       required、

5、enum
tag
import proto
升级proto文件:
升级proto
    proto文件:
  对已存在的任何字段,不能更改其标识(tag)号。
  对已存在的任何字段,不能更改其标识(tag       tag)号。
  不能添加或删除任何required的字段
  不能添加或删除任何required
                  required的字段
  optional/repeated 修饰新字段,标示新的tag
  optional/repeated修饰新字段,标示新的
                    修饰新字段,标示新的tag
                                                 8
.proto 数据编码Encoding
http://code.google.com/apis/protocolbuffers/do
cs/encoding.html
PB的序列化编码对key采用128 varint方式,能够使序列化后的二进制数
PB的序列化编码对key采用
  的序列化编码对key采用128 varint方式,能够使序列化后的二进制数
据占用空间小。Varint 是一种紧凑的表示数字的方法。它用一个或多个
据占用空间小。Varint
字节来表示一个数字,值越小的数字使用越少的字节数。这能减少用来表
示数字的字节数。([1,15][16,255])
示数字的字节数。([1,15][16,255]
           [1,15][16,255])
  变长编码的整数,它可能包含多个byte,对于每个byte的8位,其中后7位表示
  变长编码的整数,它可能包含多个byte ,对于每个byte
                       byte,对于每个 byte的 位,其中后7
  数值,最高的一位表示是否还有还有另一个byte,0表示没有,1表示有;
  数值,最高的一位表示是否还有还有另一个byte    byte, 表示没有,1
  越前面的byte表示数值的低位,后面的byte表示数值的高位;
  越前面的byte 表示数值的低位,后面的byte
         byte表示数值的低位,后面的 byte表示数值的高位;
  对于value,也是同样采用varint编码
  对于value ,也是同样采用varint
     value,也是同样采用varint编码
  key的数据含义:X YYYY ZZZ
  key的数据含义:
     的数据含义:X
    -    X表示是否还有后续的 byte来编码数字别名;
          表示是否还有后续的byte
                      byte来编码数字别名;
    -    YYYY用于编码别名,定义了超过 16个属性,则需要用到额外的 byte,一般tag应该为
         YYYY用于编码别名,定义了超过 16个属性,则需要用到额外的 byte,一般 tag应该为
             用于编码别名,定义了超过16 个属性,则需要用到额外的byte,一般tag
         [0,15]);
         [0,15]);
    -    ZZZ表示这个字段的 wireType.jpg
         ZZZ表示这个字段的
            表示这个字段的wireType.jpg


示例:required int32 a = 255; -> F8 0F 96 01
示例:required
  - required int32 a = 15; -> 78 96 01
    96   01代表的是value,二进制为: 1001 0110 0000 0001
         01代表的是 value,二进制为:
            代表的是value,二进制为:1001
    →    001 0110   000 0001(去掉最高位)
                        0001(去掉最高位)
    →    22       + 1*2^7 = 150
                                                          9
.proto 数据编码Encoding
http://code.google.com/apis/protocolbuffers/docs/encoding.h
tml#types
对于负数,PB的采用ZigZag方式进行序列化编码,将负数编码成正数。比传统的编
对于负数,PB 的采用ZigZag
     PB的采用 ZigZag方式进行序列化编码,将负数编码成正数。比传统的编
码方式节省很多空间。




 对于int32:(n << 1) ^ (n >> 31)
 对于int32
     int32:
sint32:(n << 1) ^ (n >> 63)




                                                              10
测试对比
                  vs XML
通过pb生成的序列化文件:personvs.b
通过pb 生成的序列化文件:personvs.b
  pb生成的序列化文件:
xml文件person.xml
xml文件
   文件person.xml
16进制比对:
16进制比对:




                           11
测试对比
                         vs Others
代码测试:
/pbdemo/test/demo/serializers/BenchmarkRunner.java
序列化方式:
    java custom
    java
    json(jackson) custom
    json(jackson) annotation
    json(gson)
    protobuf
关注:
    timeCreate:创建对象所需时间
    timeCreate:创建对象所需时间
    timeSerializeDifferentObjects:序列化不同对象使用的时间
    timeSerializeDifferentObjects:序列化不同对象使用的时间
    timeSerializeSameObject:序列化相同的对象使用的时间
    timeSerializeSameObject:序列化相同的对象使用的时间
    timeDeserialize:反序列化不同对象
    timeDeserialize:反序列化不同对象
    totalTime:timeSerializeDifferentObjects+timeDeserialize
    totalTime:
    length:序列化一次生成的byte长度
    length:序列化一次生成的byte长度
          :序列化一次生成的byte
结果对比
compare vs protocol buffers

                                                              12
实际应用
rest应用:设定消息头:
rest应用:设定消息头:
   Content-Type :application/x-protobuf
   Content-Type:
   将序列化的二进制内容经过http协议发送。
   将序列化的二进制内容经过http      http协议发送。
   测试工程:pbrestdemo
   测试工程:pbrestdemo
   http://www.slideshare.net/mokeefe/javaone-2009-
   ts5276-restful-protocol-buffers
下一步应用研究:将pb序列化后的数据存入到memcache中
下一步应用研究:将pb 序列化后的数据存入到memcache
                 pb序列化后的数据存入到 memcache中
   使用xmemcache ,重写
   使用xmemcache
       xmemcache,重写
   net.rubyeye.xmemcached.transcoders.SerializingTra
   nscoder serialize(Object o) 方法
                            o)方法
   参考工程:xmem
   参考工程:xmem




                                                       13
Q&A




      14

More Related Content

PPTX
Clojure概览
PPTX
Clojure的魅力
PDF
少年科技人雜誌 2015 年八月
PPTX
Ecma script edition5-小试
PDF
Programming python - part 1
PPTX
Nio trick and trap
PPTX
ES5 introduction
PPTX
SQL Loader & Bulk Insert 大量資料匯入工具
Clojure概览
Clojure的魅力
少年科技人雜誌 2015 年八月
Ecma script edition5-小试
Programming python - part 1
Nio trick and trap
ES5 introduction
SQL Loader & Bulk Insert 大量資料匯入工具

What's hot (19)

PPTX
课题一:PHP5.3、PHP5.4的特性介绍与深度挖掘
PPT
深入理解Andorid重难点
PDF
Compiler for Dummy 一點都不深入的了解 Compiler, Interpreter 和 VM
PDF
Clojure简介与应用
PPTX
函数调用关系工具-2011-孙光福
PDF
getPDF.aspx
PDF
深入淺出 Web 容器 - Tomcat 原始碼分析
PPT
Mongo db技术分享
PDF
炎炎夏日學 Android 課程 - Part1: Kotlin 語法介紹
PDF
Learning python in the motion picture industry by will zhou
PDF
Android C Library: Bionic 成長計畫
PPT
Groovy简介
PPTX
Golangintro
DOCX
Puppet安装测试
PDF
Hello world 的一生
PPT
Java7 fork join framework and closures
PDF
Ooredis
PDF
[圣思园][Java SE]Io 3
DOC
Java华为面试题
课题一:PHP5.3、PHP5.4的特性介绍与深度挖掘
深入理解Andorid重难点
Compiler for Dummy 一點都不深入的了解 Compiler, Interpreter 和 VM
Clojure简介与应用
函数调用关系工具-2011-孙光福
getPDF.aspx
深入淺出 Web 容器 - Tomcat 原始碼分析
Mongo db技术分享
炎炎夏日學 Android 課程 - Part1: Kotlin 語法介紹
Learning python in the motion picture industry by will zhou
Android C Library: Bionic 成長計畫
Groovy简介
Golangintro
Puppet安装测试
Hello world 的一生
Java7 fork join framework and closures
Ooredis
[圣思园][Java SE]Io 3
Java华为面试题
Ad

Viewers also liked (6)

PDF
Rpc原理与实现
PDF
The comet technology on Jetty
PDF
Head first in xmemcached yanf4j
PDF
Jetty(version 8)核心架构解析
PDF
ClassLoader简析
KEY
High performance network programming on the jvm oscon 2012
Rpc原理与实现
The comet technology on Jetty
Head first in xmemcached yanf4j
Jetty(version 8)核心架构解析
ClassLoader简析
High performance network programming on the jvm oscon 2012
Ad

Similar to Google protocol buffers简析 (20)

PPT
千呼萬喚始出來的Java SE 7
PPTX
Linux c++ 编程之链接与装载 -基础篇--v0.3--20120509
PPT
深入学习Mongo db
PDF
4. Go 工程化实践-0124-v2.pdf
DOCX
C语言benchmark覆盖信息收集总结4
PPT
3 hibernate映射元素和类型
PDF
2006 recycle opensourceprojects
PDF
Recycle Open Source Projects
PPTX
Win dbg入门
PPTX
Windbg入门
PPT
MongoDB Basics and Tutorial
PDF
配置Oracle 10g 双向流复制
ODP
Java DSL与动态代码生成技术的应用 (上集:DSL部分)
PDF
自由軟體鑄造場_20111023_Subversion版本控制系統之操作_曾義峰(ant)
PDF
Chapter 4 models
PPT
Django敏捷开发 刘天斯
PPT
Huangjing renren
PDF
Django development
PDF
第1讲 开始编写程序
DOC
希望科技研发部变量命名及编码规范
千呼萬喚始出來的Java SE 7
Linux c++ 编程之链接与装载 -基础篇--v0.3--20120509
深入学习Mongo db
4. Go 工程化实践-0124-v2.pdf
C语言benchmark覆盖信息收集总结4
3 hibernate映射元素和类型
2006 recycle opensourceprojects
Recycle Open Source Projects
Win dbg入门
Windbg入门
MongoDB Basics and Tutorial
配置Oracle 10g 双向流复制
Java DSL与动态代码生成技术的应用 (上集:DSL部分)
自由軟體鑄造場_20111023_Subversion版本控制系統之操作_曾義峰(ant)
Chapter 4 models
Django敏捷开发 刘天斯
Huangjing renren
Django development
第1讲 开始编写程序
希望科技研发部变量命名及编码规范

Recently uploaded (20)

PPTX
学校原版加州大学戴维斯分校毕业证UC Davis毕业证原版一比一
PPTX
学校原版卡普顿大学毕业证CBU毕业证原版一比一
PPTX
学校原版加利福尼亚大学戴维斯分校毕业证UCD毕业证原版一比一
PPTX
学校原版纽布伦斯威克大学毕业证UNB毕业证原版一比一
PPTX
学校原版堪萨斯大学毕业证UKansas毕业证原版一比一
DOCX
飼主悲傷輔導學 愛,原來是這樣的,即使結局是離別,也會用盡一生記住你教學綱要.docx
PPTX
学校原版达尔豪斯大学毕业证Dal毕业证原版一比一
PPTX
学校原版百年理工学院毕业证Centennial毕业证原版一比一
PPTX
学校原版剑桥大学毕业证Cantab毕业证原版一比一
PPTX
Introduction to Digital imgae processing
PPTX
学校原版中央兰开夏大学毕业证UCLan毕业证原版一比一
PPTX
学校原版哥伦比亚理工学院毕业证BCIT毕业证原版一比一
PPTX
学校原版汤姆逊河大学毕业证TRU毕业证原版一比一
PPTX
学校原版埃克塞特大学毕业证Exon毕业证原版一比一
PPTX
学校原版芝加哥州立大学毕业证CSU毕业证原版一比一
PPTX
学校原版韩国建国大学毕业证建大毕业证原版一比一
PPTX
学校原版加州大学戴维斯分校毕业证UCD毕业证原版一比一
PPTX
学校原版布里斯托大学毕业证Bristol毕业证原版一比一
PPTX
学校原版南澳大学毕业证UniSA毕业证原版一比一
PPTX
学校原版肯塔基大学毕业证UK毕业证原版一比一
学校原版加州大学戴维斯分校毕业证UC Davis毕业证原版一比一
学校原版卡普顿大学毕业证CBU毕业证原版一比一
学校原版加利福尼亚大学戴维斯分校毕业证UCD毕业证原版一比一
学校原版纽布伦斯威克大学毕业证UNB毕业证原版一比一
学校原版堪萨斯大学毕业证UKansas毕业证原版一比一
飼主悲傷輔導學 愛,原來是這樣的,即使結局是離別,也會用盡一生記住你教學綱要.docx
学校原版达尔豪斯大学毕业证Dal毕业证原版一比一
学校原版百年理工学院毕业证Centennial毕业证原版一比一
学校原版剑桥大学毕业证Cantab毕业证原版一比一
Introduction to Digital imgae processing
学校原版中央兰开夏大学毕业证UCLan毕业证原版一比一
学校原版哥伦比亚理工学院毕业证BCIT毕业证原版一比一
学校原版汤姆逊河大学毕业证TRU毕业证原版一比一
学校原版埃克塞特大学毕业证Exon毕业证原版一比一
学校原版芝加哥州立大学毕业证CSU毕业证原版一比一
学校原版韩国建国大学毕业证建大毕业证原版一比一
学校原版加州大学戴维斯分校毕业证UCD毕业证原版一比一
学校原版布里斯托大学毕业证Bristol毕业证原版一比一
学校原版南澳大学毕业证UniSA毕业证原版一比一
学校原版肯塔基大学毕业证UK毕业证原版一比一

Google protocol buffers简析

  • 1. A Brief View of Google Protocol Buffers 刘海波 bjhbliu@corp.netease.com 1
  • 3. 简介 GPB google开源的一种用于序列化结构化数据的协议。 google开源的一种用于序列化结构化数据的协议。 language-neutral, platform-neutral, extensible way of serializing structured data 适用于数据存储、传输 使用IDL语言描述数据格式能够,然会对描述的数据进行二 使用IDL IDL语言描述数据格式能够,然会对描述的数据进行二 进制编码。PB类似XML,但是更快(速度: XML DOM文档 进制编码。PB 类似XML ,但是更快(速度:XML DOM文档 PB类似 XML,但是更快(速度: 树)、更小(生成的二进制数据)、更简单(编码、 proto 树)、更小(生成的二进制数据)、更简单(编码、proto vs schema)。下图是官网的数据( XML DOM访问): schema)。下图是官网的数据( )。下图是官网的数据(XML DOM访问): 编码复杂度对比参考 《Coding in GPB vs XML.doc》 编码复杂度对比参考《 XML.doc》 3
  • 4. 示例 安装环境,参考《Linux 下安装Google Protocol 安装环境,参考《 ,参考《Linux 下安装Google Buffers.doc》 Buffers.doc》 .proto编写 .proto编写 编译生成目标类: 命令行:protoc -I=$SRC_DIR –java_out=$DST_DIR 命令行:protoc $SRC_DIR/addressbook.proto 注:-I指定.proto文件所 注:-I 指定.proto -I指定 .proto文件所 在目录 –java_out 指定生成java文件所在的目录 java_out指定生成 java文件所在的目录 指定生成java eclipse:protoclipse 插件 eclipse: protoclipse插件 代码: pbdemotestaddress : pbdemotestaddress: ListPeople.java 、 AddPerson.java ListPeople.java、 pbdemotestcomexampletutorialAddressBookProtos.java pbdemotestdemoprotoaddressbook.proto 4
  • 5. 示例 解析AddressBookProtos.java 解析AddressBookProtos.java 编译生成目标类: 命令行:protoc -I=$SRC_DIR –java_out=$DST_DIR 命令行:protoc $SRC_DIR/addressbook.proto 注:-I指定.proto文件所在目录 注:-I 指定.proto -I指定.proto文件所在目录 java_out指定生成java文件所在的目录 –java_out指定生成java文件所在的目录 指定生成java eclipse:protoclipse插件 eclipse:protoclipse插件 代码: pbdemotestaddress : pbdemotestaddress: ListPeople.java 、 AddPerson.java ListPeople.java、 pbdemotestcomexampletutorialAddressBookProtos.java pbdemotestdemoprotoaddressbook.proto java文件中的类结构: java文件中的类结构: class AddressBookProtos{ class Person{ class PhoneNumber{class Builder{} } PhoneNumber{class class Builder{} } class AddressBook{class Builder{} } AddressBook{class } 5
  • 6. 示例 序列化/反序列化分析 所有的实体类都没有 setter方法,只有getter方法,相应的builder类中有setter方法 所有的实体类都没有setter方法,只有getter方法,相应的builder类中有setter setter方法,只有 getter方法,相应的 builder类中有 setter方法 通过查看代码可以看到,以上三个类的成员变量都是private类型的,而 通过查看代码可以看到,以上三个类的成员变量都是private类型的,而 查看代码可以看到,以上三个类的成员变量都是private类型的, 且只提供getter方法,而没有提供setter方法去为数据变量赋值。 只提供getter方法,而没有提供setter getter方法,而没有提供setter方法去为数据变量赋值。 PB利用了内部类可以访问到外部类中私有成员变量的特性。对外部类的任 PB利用了内部类可以访问到外部类中私有成员变量的特性。对外部类的任 何赋值操作都需要通过Builder内部类来进行。当调用Builder的build() 何赋值操作都需要通过Builder内部类来进行。当调用Builder Builder内部类来进行。 Builder的 方法时,会在方法体内创建一个指向外部类的引用(名为result),当赋 方法时,会在方法体内创建一个指向外部类的引用(名为result 会在方法体内创建一个指向外部类的引用(名为result),当赋 值完成,会把这个对象返回。 PB通过这样一种方式保证了数据安全性,一旦数据构建完毕,将无法再对 PB通过这样一种方式保证了数据安全性,一旦数据构建完毕,将无法再对 其进行修改。 6
  • 7. 示例 序列化/反序列化分析 一句话就可以实现反序列化:AddressBook addressBook = AddressBook.parseFrom(new FileInputStream(filePath); PB在parseFrom 后面做的事情: PB在parseFrom后面做的事情: 根据inputStream或者buffer去构造一个CodedInputStream; 根据inputStream或者buffer去构造一个CodedInputStream inputStream或者buffer去构造一个CodedInputStream; 然后使用生成代码中的mergeFrom方法,去解析二进制数据: 然后使用生成代码中的mergeFrom mergeFrom方法,去解析二进制数据: - 首先调用CodedInputStream的readTag,也就是从中取得key值 首先调用CodedInputStream readTag,也就是从中取得key值 CodedInputStream的 ,也就是从中取得key (int类型),然后根据tag找到field int类型),然后根据tag找到 类型),然后根据tag找到field - 然后通过swtich块来往对象中赋值(PB采用了Base 128 然后通过swtich块来往对象中赋值(PB采用了Base swtich块来往对象中赋值(PB采用了 Varints的方式来编码这个数字)。 Varints的方式来编码这个数字)。 将数据解析完成后,会调用build()方法,将构建好的对象返回。 将数据解析完成后,会调用build() build()方法,将构建好的对象返回。 注:在这个过程中要通过PB提供的Descriptor类还获取每个字段的 注:在这个过程中要通过PB提供的Descriptor PB提供的Descriptor类还获取每个字段的 描述信息。 7
  • 8. .proto文件语法 http://code.google.com/apis/protocolbuffers/do cs/proto.html java类是编译器根据proto文件生成的。作为一个IDL语言, java类是编译器根据 proto文件生成的。作为一个 IDL语言, 类是编译器根据proto 文件生成的。作为一个IDL proto有相应的语法。 proto有相应的语法。 1、package:proto文件以一个package声明开始。这个声明是 package: proto文件以一个 package声明开始。这个声明是 文件以一个package 为了防止不同项目之间的命名冲突。(proto文件的import) 为了防止不同项目之间的命名冲突。(proto 文件的import proto文件的 import) 2、java_package 3、java_outer_classname :定义所有message类的容器类。 java_outer_classname:定义所有 message类的容器类。 :定义所有message 4、message:一组类型字段的集合。同时被message修饰过的字 message:一组类型字段的集合。同时被 message修饰过的字 :一组类型字段的集合。同时被message 段,也可以当做类型,用于Nested message 声明中。 段,也可以当做类型,用于Nested message声明中。 常用类型:WireType.doc 常用类型:WireType.doc 字段修饰:required、optional、repeated 字段修饰:required optional、 required、 5、enum tag import proto 升级proto文件: 升级proto proto文件: 对已存在的任何字段,不能更改其标识(tag)号。 对已存在的任何字段,不能更改其标识(tag tag)号。 不能添加或删除任何required的字段 不能添加或删除任何required required的字段 optional/repeated 修饰新字段,标示新的tag optional/repeated修饰新字段,标示新的 修饰新字段,标示新的tag 8
  • 9. .proto 数据编码Encoding http://code.google.com/apis/protocolbuffers/do cs/encoding.html PB的序列化编码对key采用128 varint方式,能够使序列化后的二进制数 PB的序列化编码对key采用 的序列化编码对key采用128 varint方式,能够使序列化后的二进制数 据占用空间小。Varint 是一种紧凑的表示数字的方法。它用一个或多个 据占用空间小。Varint 字节来表示一个数字,值越小的数字使用越少的字节数。这能减少用来表 示数字的字节数。([1,15][16,255]) 示数字的字节数。([1,15][16,255] [1,15][16,255]) 变长编码的整数,它可能包含多个byte,对于每个byte的8位,其中后7位表示 变长编码的整数,它可能包含多个byte ,对于每个byte byte,对于每个 byte的 位,其中后7 数值,最高的一位表示是否还有还有另一个byte,0表示没有,1表示有; 数值,最高的一位表示是否还有还有另一个byte byte, 表示没有,1 越前面的byte表示数值的低位,后面的byte表示数值的高位; 越前面的byte 表示数值的低位,后面的byte byte表示数值的低位,后面的 byte表示数值的高位; 对于value,也是同样采用varint编码 对于value ,也是同样采用varint value,也是同样采用varint编码 key的数据含义:X YYYY ZZZ key的数据含义: 的数据含义:X - X表示是否还有后续的 byte来编码数字别名; 表示是否还有后续的byte byte来编码数字别名; - YYYY用于编码别名,定义了超过 16个属性,则需要用到额外的 byte,一般tag应该为 YYYY用于编码别名,定义了超过 16个属性,则需要用到额外的 byte,一般 tag应该为 用于编码别名,定义了超过16 个属性,则需要用到额外的byte,一般tag [0,15]); [0,15]); - ZZZ表示这个字段的 wireType.jpg ZZZ表示这个字段的 表示这个字段的wireType.jpg 示例:required int32 a = 255; -> F8 0F 96 01 示例:required - required int32 a = 15; -> 78 96 01 96 01代表的是value,二进制为: 1001 0110 0000 0001 01代表的是 value,二进制为: 代表的是value,二进制为:1001 → 001 0110 000 0001(去掉最高位) 0001(去掉最高位) → 22 + 1*2^7 = 150 9
  • 10. .proto 数据编码Encoding http://code.google.com/apis/protocolbuffers/docs/encoding.h tml#types 对于负数,PB的采用ZigZag方式进行序列化编码,将负数编码成正数。比传统的编 对于负数,PB 的采用ZigZag PB的采用 ZigZag方式进行序列化编码,将负数编码成正数。比传统的编 码方式节省很多空间。 对于int32:(n << 1) ^ (n >> 31) 对于int32 int32: sint32:(n << 1) ^ (n >> 63) 10
  • 11. 测试对比 vs XML 通过pb生成的序列化文件:personvs.b 通过pb 生成的序列化文件:personvs.b pb生成的序列化文件: xml文件person.xml xml文件 文件person.xml 16进制比对: 16进制比对: 11
  • 12. 测试对比 vs Others 代码测试: /pbdemo/test/demo/serializers/BenchmarkRunner.java 序列化方式: java custom java json(jackson) custom json(jackson) annotation json(gson) protobuf 关注: timeCreate:创建对象所需时间 timeCreate:创建对象所需时间 timeSerializeDifferentObjects:序列化不同对象使用的时间 timeSerializeDifferentObjects:序列化不同对象使用的时间 timeSerializeSameObject:序列化相同的对象使用的时间 timeSerializeSameObject:序列化相同的对象使用的时间 timeDeserialize:反序列化不同对象 timeDeserialize:反序列化不同对象 totalTime:timeSerializeDifferentObjects+timeDeserialize totalTime: length:序列化一次生成的byte长度 length:序列化一次生成的byte长度 :序列化一次生成的byte 结果对比 compare vs protocol buffers 12
  • 13. 实际应用 rest应用:设定消息头: rest应用:设定消息头: Content-Type :application/x-protobuf Content-Type: 将序列化的二进制内容经过http协议发送。 将序列化的二进制内容经过http http协议发送。 测试工程:pbrestdemo 测试工程:pbrestdemo http://www.slideshare.net/mokeefe/javaone-2009- ts5276-restful-protocol-buffers 下一步应用研究:将pb序列化后的数据存入到memcache中 下一步应用研究:将pb 序列化后的数据存入到memcache pb序列化后的数据存入到 memcache中 使用xmemcache ,重写 使用xmemcache xmemcache,重写 net.rubyeye.xmemcached.transcoders.SerializingTra nscoder serialize(Object o) 方法 o)方法 参考工程:xmem 参考工程:xmem 13
  • 14. Q&A 14