protobuf在java中的应用

一、protobuf的应用场景

在官方文档中可以看到
protocol buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。
Protocol Buffers 是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 XML,但是比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单
可以看到protobuf 与json相比具有 压缩比高 、解压缩速度更快的优点
 
二、protobuf的使用

protobuf在使用上较为复杂,过程可以分为以下几步:
  1. 编写java 的POJO类
  2. 通过工具将java的POJO类,生成protobuf数据格式下的(在idea中可以下载Pojo2Proto插件)
  3. 新建一个以.proto的文件,并写入Pojo2Proto插件生成数据
  4. 通过proto.exe程序将.proto文件编译生成java类,该JAVA类中定义有PB对该类的数据格式定义、get/set操作、解/压锁数据的方法
 
POJO类数据:
public class Entity {
    private String key;
    private String value;
    public String getKey() {
        return key;
    }
    public void setKey(String key) {
        this.key = key;
    }
    public String getValue() {
        return value;
    }
    public void setValue(String value) {
        this.value = value;
    }
}

生成的protobuf的数据:

syntax = "proto3";

message Entity {
   string key = 1;
   string value = 2;
}

通过protoc.exe进行编译

编译Entity.proto文件
protoc-3.9.2-windows-x86_64.exe  ./src/main/proto/Entity.proto --java_out=./src/main/java/src/
编译后生成有 StreamWrap 类的文件,生成的StreamWrap类代码量非常大,但我们所关注的功能主要是序列化、反序列化及数据的读写操作
 
 
通过 StreamWrap压缩数据
StreamWrap.Entity.Builder builder = StreamWrap.Entity.newBuilder();
//构造数据
builder.setKey("123");
builder.setValue("123");
StreamWrap.Entity entity = builder.build();
//将该PB类转换为二进制数据格式
byte[] buff = entity.toByteArray();
通过 StreamWrap 解压缩数据
StreamWrap.Entity entity = StreamWrap.Entity.parseFrom(buff);
三、protoBuf的性能测试

 
模拟产生多条数据,分别对数据进行JSON格式的序列化、反序列化,并记录 序列化时间、反序列化时间、占用空间大小
再对同样的数据进行PB格式下的 序列化、反序列化,并记录序列化时间、反序列化时间、占用空间大小
通过对比两种格式下的序列化时间、反序列化时间、占用空间大小来评估PB的性能
package src.entity;

import com.google.gson.Gson;
import com.google.protobuf.InvalidProtocolBufferException;
import src.proto.StreamWrap;
import src.proto.TradeOuterClass2;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

public class Ser {
//      定义数据的条数
    private static int NUM = 100000;
    public static void main(String[] args) throws InterruptedException, InvalidProtocolBufferException, UnsupportedEncodingException {
        List<byte[]> list = new ArrayList<>();
        //构造数据
        Long start1 = System.currentTimeMillis();
        for (int i = 0 ; i<NUM;i++) {
            TradeOuterClass2.Trade.Builder builder = TradeOuterClass2.Trade.newBuilder();
            builder.setTradingDay("20191230");
            builder.setSettlementGroupID("SD01");
            builder.setSettleMentID("1");
            builder.setParticipantID("0001");
            builder.setClientID("00000001");
            builder.setUserID("TECHOP");
            builder.setInstrumentID("ITIT");
            builder.setOrderSysID("51");
            TradeOuterClass2.Trade trade = builder.build();
            byte[] buff = trade.toByteArray();
            System.out.println(buff.length);
            if (i % 100 == 0 )
            Thread.sleep(1);
            list.add(buff);
        }
        System.out.println("ProtoBuf 数据长度:" + list.toString().getBytes().length);
        System.out.println("ProtoBuf 压缩时间:" + (System.currentTimeMillis() - start1));

        Gson gson = new Gson();
        List<String> list2 = new ArrayList<>();
        Long start2 = System.currentTimeMillis();
        for (int i = 0 ; i<NUM;i++) {
            Trade2 trade1 = new Trade2();
            trade1.setTradingDay("20191230");
            trade1.setSettlementGroupID("SD01");
            trade1.setSettleMentID(1);
            trade1.setParticipantID("0001");
            trade1.setClientID("000000001");
            trade1.setUserID("TECHOP");
            trade1.setInstrumentID("ITIT");
            trade1.setOrderSysID("51");
            System.out.println(trade1.toString().getBytes().length);
            if (i % 100 == 0 )
            list2.add(gson.toJson(trade1));
        }
        System.out.println("JSon 数据长度:" + list2.toString().getBytes().length);
        System.out.println("JSon 压缩时间:" + (System.currentTimeMillis() - start2));

        long start3 = System.currentTimeMillis();
        for (byte[] buff : list){
            TradeOuterClass2.Trade trade = TradeOuterClass2.Trade.parseFrom(buff);
        }
        System.out.println("ProtoBuf 解压缩时间:" + (System.currentTimeMillis() - start3));

        long start4 = System.currentTimeMillis();
        for (String string : list2){
            Trade trade = gson.fromJson(string,Trade.class);
        }
        System.out.println("JSon 解压缩时间:" + (System.currentTimeMillis() - start4));
    }
}
 
 
case 1 : 对一条数据进行序列化、反序列化
 
数据大小
序列化时间(ms)
反序列化时间(ms)
Protobuf
136
72
4
JSON
235
25
3
 
case2:对10万条数据进行序列化和反序列化
 
数据大小
序列化时间(ms)
反序列化时间(ms)
Protobuf
6500071
490
176
JSON
17700058
662
361
 
经过实验对比可以发现,PB的压缩比是JSON压缩数据的 三倍(如果单条数据内容更大,会产生更大的压缩比)。
 
当数据量较小的情况下,JSON的序列化时间和反序列化时间是远快于的PB的,当数据条数较大的情况时,PB的序列化时间和反序列化时间则更占优势。
 
四、关于数据格式的一些思考

 
常用的数据格式包括有XML、JSON以及Protobuf,这三种数据格式都是 结构化数据,也能够完成数据的 序列化。
 
1、Protobuf具备更好的序列化能力,尤其是在做数据仓库的时候,PB能够更好的完成数据压缩,节省存储资源
2、在数据条数较多的情况下,PB序列化、反序列化的时间占有更大的优势
3、由于ProtoBuf在序列化数据的时候存储为二进制数据,可读性极差,因此在应用场景方面,Protobuf的应用场景较窄
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值