Protobuf简介

    什么是 Google Protocol Buffer? 假如您在网上搜索,应该会得到类似这样的文字介绍:
    Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准,目前已经正在使用的有超过 48,162 种报文格式定义和超过 12,183 个 .proto 文件。他们用于 RPC 系统和持续数据存储系统。
    Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了 C++、Java、Python 三种语言的 API。
    或许您和我一样,在第一次看完这些介绍后还是不明白 Protobuf 究竟是什么,那么我想一个简单的例子应该比较有助于理解它。

一个简单的例子

安装 Google Protocol Buffer

https://github.com/protocolbuffers/protobuf/releases/tag/v3.17.3

安装步骤如下所示:

tar -xzf protobuf-all-3.17.3.tar.gz
cd protobuf-3.17.3
./configure
make && make install

关于简单例子的描述

书写 .proto 文件

phone. proto

syntax = "proto2";
package cn.org.wyxxt;
message PhoneDetail {
    required string dnum = 1;
    required string length = 2;
    required string type = 3;
    required string date = 4;
}

编译 .proto 文件

/usr/local/bin/protoc phone.proto -help

/usr/local/bin/protoc phone.proto --java_out=/root/

编写代码

@Test
  public void insertByProtoBuf() throws ParseException, IOException {
    List<Put> puts = new ArrayList<>();
    for (int i = 0; i < 10; i++) {
      String phoneNumber = getNumber("158");
      for (int j = 0; j < 10000; j++) {
        String dnum = getNumber("177");
        String length = String.valueOf(random.nextInt(100));
        String date = getDate("2019");
        String type = String.valueOf(random.nextInt(2));
        // rowKey
        String rowKey = phoneNumber + "_" + (Long.MAX_VALUE - sdf.parse(date).getTime());

        Phone.PhoneDetail.Builder builder = Phone.PhoneDetail.newBuilder();
        builder.setDate(date);
        builder.setDnum(dnum);
        builder.setLength(length);
        builder.setType(type);
        Put put = new Put(Bytes.toBytes(rowKey));
        put.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("phone"), builder.build().toByteArray());
        puts.add(put);
      }
    }
    table.put(puts);
  }


@Test
  public void getByProtoBuf() throws IOException {
    Get get = new Get(Bytes.toBytes("15894400392_9223370487438904807"));
    Result rs = table.get(get);
    byte[] b =
        CellUtil.cloneValue(rs.getColumnLatestCell(Bytes.toBytes("cf"), Bytes.toBytes("phone")));
    Phone.PhoneDetail phoneDetail = Phone.PhoneDetail.parseFrom(b);
    System.out.println(phoneDetail);
  }

和其他类似技术的比较

看完这个简单的例子之后,希望您已经能理解 Protobuf 能做什么了,那么您可能会说,世上还有很多其他的类似技术啊,比如 XML,JSON,Thrift 等等。和他们相比,Protobuf 有什么不同呢?
简单说来 Protobuf 的主要优点就是:简单,快。
这有测试为证,项目 thrift-protobuf-compare 比较了这些类似的技术
Total Time 指一个对象操作的整个时间,包括创建对象,将对象序列化为内存中的字节序列,然后再反序列化的整个过程。从测试结果可以看到 Protobuf 的成绩很好,感兴趣的读者可以自行到网站 http://code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking 上了解更详细的测试结果。

Protobuf 的优点

Protobuf 有如 XML,不过它更小、更快、也更简单。你可以定义自己的数据结构,然后使用代码生成器生成的代码来读写这个数据结构。你甚至可以在无需重新部署程序的情况下更新数据结构。只需使用 Protobuf 对数据结构进行一次描述,即可利用各种不同语言或从各种不同数据流中对你的结构化数据轻松读写。
它有一个非常棒的特性,即“向后”兼容性好,人们不必破坏已部署的、依靠“老”数据格式的程序就可以对数据结构进行升级。这样您的程序就可以不必担心因为消息结构的改变而造成的大规模的代码重构或者迁移的问题。因为添加新的消息中的 field 并不会引起已经发布的程序的任何改变。
Protobuf 语义更清晰,无需类似 XML 解析器的东西(因为 Protobuf 编译器会将 .proto 文件编译生成对应的数据访问类以对 Protobuf 数据进行序列化、反序列化操作)。
使用 Protobuf 无需学习复杂的文档对象模型,Protobuf 的编程模式比较友好,简单易学,同时它拥有良好的文档和示例,对于喜欢简单事物的人们而言,Protobuf 比其他的技术更加有吸引力。

Protobuf 的不足

Protbuf 与 XML 相比也有不足之处。它功能简单,无法用来表示复杂的概念。
XML 已经成为多种行业标准的编写工具,Protobuf 只是 Google 公司内部使用的工具,在通用性上还差很多。
由于文本并不适合用来描述数据结构,所以 Protobuf 也不适合用来对基于文本的标记文档(如 HTML)建模。另外,由于 XML 具有某种程度上的自解释性,它可以被人直接读取编辑,在这一点上 Protobuf 不行,它以二进制的方式存储,除非你有 .proto 定义,否则你没法直接读出 Protobuf 的任何内容。
Scroll to Top