`
agapple
  • 浏览: 1595474 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

几种序列化协议(protobuf,xstream,jackjson,jdk,hessian)相关数据对比

    博客分类:
  • java
阅读更多

最近研究了下google protobuf协议,顺便对比了一下json,xml,java序列化相关的数据对比,从几个纬度进行对比。

 

别人的相关测试数据: http://code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking

 

测试纬度

  • 序列化时间
  • 反序列化时间
  • bytes大小

测试代码

准备protobuf文件

 

import "InnerMessage.proto";
package demo; 
option java_package = "com.agapple.protobuf.data";
option java_outer_classname = "MessageProtos";
option optimize_for = SPEED ;  //CODE_SIZE,LITE_RUNTIME
option java_generic_services = false;
message Message {
	
	required string strObj = 1 [default="hello"];
	optional int32 int32Obj = 2;
	optional int64 int64Obj = 3;
	optional uint32 uint32Obj = 4;
	optional uint64 uint64Obj = 5;
	optional sint32 sint32Obj = 6;
	optional sint64 sint64Obj = 7;
	optional fixed32 fixed32Obj = 8;
	optional fixed64 fixed64Obj = 9;
	optional sfixed32 sfixed32Obj = 10;
	optional sfixed64 sfixed64Obj = 11;
	optional bool 	boolObj = 12;
	optional bytes 	bytesObj = 13;
	optional float folatObj = 14 [deprecated=true];
	repeated double doubleObj = 15 [packed=true]; //
	optional InnerMessage innerMessage = 16;
}

 

 

import "EnumType.proto";

package demo; 
option java_package = "com.agapple.protobuf.data";
option java_outer_classname = "InnerMessageProtos";

message InnerMessage { 
	optional string name = 1 [default = "name"];
	optional int32 id = 2;
	optional EnumType type = 3 [default = UNIVERSAL];
}

 

 

package demo; 
option java_package = "com.agapple.protobuf.data";
option java_outer_classname = "EnumTypeProtos";

enum EnumType {
	UNIVERSAL = 0; 
	WEB = 1; 
	IMAGES = 2; 
	LOCAL = 3; 
	NEWS = 4; 
	PRODUCTS = 5; 
	VIDEO = 6; 
}

 

 

基本上把protobuf支持的类型都囊括了,包括嵌套类型,枚举类型,以及各种int,uint,bool,bytes。  

 

依赖关系是Message.proto依赖了InnerMessage对象,而InnerMessage对象里包含了一个自定义枚举类型EnumType。

 

关于类型的使用可参见: 
      http://code.google.com/intl/zh/apis/protocolbuffers/docs/reference/java-generated.html
      http://code.google.com/intl/zh/apis/protocolbuffers/docs/proto.html

 

 

 

生成protobuf javabean

 

 

cd /home/ljh/work/code/src/main/java

/home/ljh/work/protobuf/bin/protoc --proto_path=com/agapple/protobuf/ --java_out=. com/agapple/protobuf/EnumType.proto
/home/ljh/work/protobuf/bin/protoc --proto_path=com/agapple/protobuf/ --java_out=. com/agapple/protobuf/InnerMessage.proto
/home/ljh/work/protobuf/bin/protoc --proto_path=com/agapple/protobuf/ --java_out=. com/agapple/protobuf/Message.proto

 

 通过protobuf自带的protoc进行编译,指定了protobuf文件的路径, 具体的文档: http://code.google.com/intl/zh/apis/protocolbuffers/docs/proto.html#generating

 

 

运行脚本后就会生成对应的3个javabean文件: MessageProtos , InnerMessageProtos , EnumTypeProtos。

 

最后构造测试的protobuf bean代码

 

private static MessageProtos.Message getProtobufBean() {
        com.agapple.protobuf.data.MessageProtos.Message.Builder messageBuilder = MessageProtos.Message.newBuilder();

        messageBuilder.setStrObj("message");
        messageBuilder.setFolatObj(1f);
        messageBuilder.addDoubleObj(1d);
        messageBuilder.addDoubleObj(2d);
        messageBuilder.setBoolObj(true);

        messageBuilder.setBytesObj(ByteString.copyFrom(new byte[] { 1, 2, 3 }));
        messageBuilder.setInt32Obj(32);
        messageBuilder.setInt64Obj(64l);
        messageBuilder.setSint32Obj(232);
        messageBuilder.setSint64Obj(264);
        messageBuilder.setFixed32Obj(532);
        messageBuilder.setFixed64Obj(564);
        messageBuilder.setSfixed32Obj(2532);
        messageBuilder.setSfixed64Obj(2564);
        messageBuilder.setUint32Obj(632);
        messageBuilder.setUint64Obj(664);

        com.agapple.protobuf.data.InnerMessageProtos.InnerMessage.Builder innerMessageBuilder = InnerMessageProtos.InnerMessage.newBuilder();
        innerMessageBuilder.setId(1);
        innerMessageBuilder.setName("inner");
        innerMessageBuilder.setType(EnumType.PRODUCTS);

        messageBuilder.setInnerMessage(innerMessageBuilder);

        return messageBuilder.build();
    }

 

 

 

准备纯Pojo Bean 

同样的,为了和json , xml以及java序列化有个很好的对比,新建了3个纯的pojo bean:  MessagePojo , InnerMessagePojo , EnumTypePojo。

属性和proto的bean保持一致。

 

构建bean对象

 

private static MessagePojo getPojoBean() {
        MessagePojo bean = new MessagePojo();

        bean.setStrObj("message");
        bean.setFolatObj(1f);
        List<Double> doubleObj = new ArrayList<Double>();
        doubleObj.add(1d);
        doubleObj.add(2d);
        bean.setDoubleObj(doubleObj);
        bean.setBoolObj(true);

        bean.setBytesObj(new byte[] { 1, 2, 3 });
        bean.setInt32Obj(32);
        bean.setInt64Obj(64l);
        bean.setSint32Obj(232);
        bean.setSint64Obj(264);
        bean.setFixed32Obj(532);
        bean.setFixed64Obj(564);
        bean.setSfixed32Obj(2532);
        bean.setSfixed64Obj(2564);
        bean.setUint32Obj(632);
        bean.setUint64Obj(664);

        InnerMessagePojo innerMessagePojo = new InnerMessagePojo();
        innerMessagePojo.setId(1);
        innerMessagePojo.setName("inner");
        innerMessagePojo.setType(EnumTypePojo.PRODUCTS);

        bean.setInnerMessage(innerMessagePojo);

        return bean;
    }

 

 

 

具体的测试代码

定义测试Template接口

 

interface TestCallback {

    String getName();

    byte[] writeObject(Object source);

    Object readObject(byte[] bytes);
}

 

 

统一的测试模板

 

private static void testTemplate(TestCallback callback, Object source, int count) {
        int warmup = 10;
        // 先进行预热,加载一些类,避免影响测试
        for (int i = 0; i < warmup; i++) {
            byte[] bytes = callback.writeObject(source);
            callback.readObject(bytes);
        }
        restoreJvm(); // 进行GC回收
        // 进行测试
        long start = System.nanoTime();
        long size = 0l;
        for (int i = 0; i < count; i++) {
            byte[] bytes = callback.writeObject(source);
            size = size + bytes.length;
            callback.readObject(bytes);
            // System.out.println(callback.readObject(bytes));
            bytes = null;
        }
        long nscost = (System.nanoTime() - start);
        System.out.println(callback.getName() + " total cost=" + integerFormat.format(nscost) + "ns , each cost="
                           + integerFormat.format(nscost / count) + "ns , and byte sizes = " + size / count);
        restoreJvm();// 进行GC回收

    }

 

 

  在测试模板方法中,使用了warmup预热的概念,就是预先执行目标方法一定的次数,用于避免因为jit的优化影响系统测试。 同时包含了每次测试模板调用完成后system.gc保证下一轮的功能测试

 

  相应的restoreJvm方法: 

private static void restoreJvm() {
        int maxRestoreJvmLoops = 10;
        long memUsedPrev = memoryUsed();
        for (int i = 0; i < maxRestoreJvmLoops; i++) {
            System.runFinalization();
            System.gc();

            long memUsedNow = memoryUsed();
            // break early if have no more finalization and get constant mem used
            if ((ManagementFactory.getMemoryMXBean().getObjectPendingFinalizationCount() == 0)
                && (memUsedNow >= memUsedPrev)) {
                break;
            } else {
                memUsedPrev = memUsedNow;
            }
        }
    }

    private static long memoryUsed() {
        Runtime rt = Runtime.getRuntime();
        return rt.totalMemory() - rt.freeMemory();
    }

 

最后相应的测试例子:

 

        final int testCount = 1000 * 500;        
        final MessageProtos.Message protoObj = getProtobufBean();
        final MessagePojo pojoOBj = getPojoBean();

        // Serializable测试
        testTemplate(new TestCallback() {

            public String getName() {
                return "Serializable Test";
            }

            @Override
            public byte[] writeObject(Object source) {
                try {
                    ByteArrayOutputStream bout = new ByteArrayOutputStream();
                    ObjectOutputStream output = new ObjectOutputStream(bout);
                    output.writeObject(source);
                    return bout.toByteArray();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }

            @Override
            public Object readObject(byte[] bytes) {
                try {
                    ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
                    ObjectInputStream input = new ObjectInputStream(bin);
                    return input.readObject();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return null;
            }
        }, pojoOBj, testCount);

        // protobuf测试
        testTemplate(new TestCallback() {

            public String getName() {
                return "protobuf test";
            }

            @Override
            public byte[] writeObject(Object source) {
                if (source instanceof MessageProtos.Message) {
                    MessageProtos.Message message = (MessageProtos.Message) source;
                    return message.toByteArray();
                }

                return null;
            }

            @Override
            public Object readObject(byte[] bytes) {
                try {
                    return MessageProtos.Message.parseFrom(bytes);
                } catch (InvalidProtocolBufferException e) {
                    e.printStackTrace();
                }
                return null;
            }
        }, protoObj, testCount);

        // json测试
        final ObjectMapper objectMapper = new ObjectMapper();
        final JavaType javaType = TypeFactory.type(pojoOBj.getClass());

        // JSON configuration not to serialize null field
        objectMapper.getSerializationConfig().setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);

        // JSON configuration not to throw exception on empty bean class
        objectMapper.getSerializationConfig().disable(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS);

        // JSON configuration for compatibility
        objectMapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        objectMapper.configure(Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);

        testTemplate(new TestCallback() {

            public String getName() {
                return "Jackson Test";
            }

            @Override
            public byte[] writeObject(Object source) {
                try {
                    return objectMapper.writeValueAsBytes(source);
                } catch (JsonGenerationException e) {
                    e.printStackTrace();
                } catch (JsonMappingException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                return null;
            }

            @Override
            public Object readObject(byte[] bytes) {
                try {
                    return objectMapper.readValue(bytes, 0, bytes.length, javaType);
                } catch (JsonParseException e) {
                    e.printStackTrace();
                } catch (JsonMappingException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }
        }, pojoOBj, testCount);

        // Xstream测试
        final XStream xstream = new XStream();
        testTemplate(new TestCallback() {

            public String getName() {
                return "Xstream test";
            }

            @Override
            public byte[] writeObject(Object source) {
                return xstream.toXML(source).getBytes();
            }

            @Override
            public Object readObject(byte[] bytes) {
                return xstream.fromXML(new ByteArrayInputStream(bytes));
            }
        }, pojoOBj, testCount);

 

 

2011年3月10号补充 =========================================================

增加了hessian 3.1.5版本基于二进制序列化的测试

 

<dependency>
    <groupId>com.caucho</groupId>
    <artifactId>hessian</artifactId>
    <version>3.1.5</version>
</dependency>

 

 

测试了3种情况:

 

  1. hessian 2协议
  2. hessian 2协议 + deflat压缩
  3. hessian 1协议

 

 

测试代码:

 

// hessian 2 with no deflat
        testTemplate(new TestCallback() {

            public String getName() {
                return "hessian 2 with no deflat";
            }

            @Override
            public byte[] writeObject(Object source) {
                try {
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    Hessian2Output out = new Hessian2Output(bos);
                    // out.startMessage();
                    out.writeObject(source);
                    // out.completeMessage();
                    out.flush();
                    return bos.toByteArray();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }

            @Override
            public Object readObject(byte[] bytes) {
                try {
                    ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
                    Hessian2Input in = new Hessian2Input(bin);
                    // in.startMessage();
                    Object obj = in.readObject();
                    // in.completeMessage();
                    return obj;
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }
        }, pojoOBj, testCount);

        // hessian 2 with deflat
        final Deflation envelope = new Deflation();
        testTemplate(new TestCallback() {

            public String getName() {
                return "hessian 2 with deflat";
            }

            @Override
            public byte[] writeObject(Object source) {
                try {
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    Hessian2Output out = new Hessian2Output(bos);
                    out = envelope.wrap(out);
                    out.writeObject(source);
                    out.flush();
                    out.close(); // 记得关闭
                    return bos.toByteArray();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return null;
            }

            @Override
            public Object readObject(byte[] bytes) {
                try {
                    ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
                    Hessian2Input in = new Hessian2Input(bin);
                    in = envelope.unwrap(in);
                    Object obj = in.readObject();
                    in.close();
                    return obj;
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }
        }, pojoOBj, testCount);

        // hessian 1 with no deflat
        testTemplate(new TestCallback() {

            public String getName() {
                return "hessian 1 with no deflat";
            }

            @Override
            public byte[] writeObject(Object source) {
                try {
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    HessianOutput out = new HessianOutput(bos);
                    out.writeObject(source);
                    out.flush();
                    return bos.toByteArray();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return null;
            }

            @Override
            public Object readObject(byte[] bytes) {
                try {
                    ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
                    HessianInput in = new HessianInput(bin);
                    Object obj = in.readObject();
                    in.close();
                    return obj;
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }
        }, pojoOBj, testCount);
 

 


测试结果

序列化数据对比



 

bytes字节数对比

具体的数字: 

protobuf jackson xstream Serializable hessian2 hessian2压缩 hessian1
序列化(单位ns) 1154 5421  92406  10189 26794 100766 29027
反序列化(单位ns) 1334 8743  117329  64027 37871 188432 37596
bytes 97 311  664  824 374 283 495

 

  1. protobuf 不管是处理时间上,还是空间占用上都优于现有的其他序列化方式。内存暂用是java 序列化的1/9,时间也是差了一个数量级,一次操作在1us左右。缺点:就是对象结构体有限制,只适合于内部系统使用。
  2. json格式在空间占用还是有一些优势,是java序列化的1/2.6。序列化和反序列化处理时间上差不多,也就在5us。当然这次使用的jackson,如果使用普通的jsonlib可能没有这样好的性能,jsonlib估计跟java序列化差不多。
  3. xml相比于java序列化来说,空间占用上有点优势,但不明显。处理时间上比java序列化多了一个数量级,在100us左右。
  4. 以前一种的java序列化,表现得有些失望
  5. hessian测试有点意外,具体序列化数据上还步入json。性能上也不如jackjson,输得比较彻底。
  6. hessian使用压缩,虽然在字节上有20%以上的空间提升,但性能上差了4,5倍,典型的以时间换空间。总的来说还是google protobuf比较给力

 

总结 

以后在内部系统,数据cache存储上可以考虑使用protobuf。跟外部系统交互上可以考虑使用json。

 

有兴趣的同学,可以研究一下google protobuf的marshall的方式: http://code.google.com/intl/zh/apis/protocolbuffers/docs/encoding.html

  • 大小: 11.4 KB
  • 大小: 13.8 KB
分享到:
评论
7 楼 flashAI 2015-11-19  
  
6 楼 fanwenqiang666 2013-12-16  
现在项目变更太频繁的情况下 虽然已经不用序列化来作为项目应用了,还是要研究一下。
5 楼 huhang1986 2012-06-18  
为什么结果跟http://code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking有差异,仔细查过没
4 楼 agapple 2011-08-05  
nextw3 写道
jackson和xstream不是序列化协议吧,只是序列化的工具而已...


恩是的,只是xml和json两种协议,这两种工具刚好是使用的比较广泛。现在有fastjson,avro据说性能都比protobuf要好
3 楼 nextw3 2011-08-05  
jackson和xstream不是序列化协议吧,只是序列化的工具而已...
2 楼 agapple 2011-02-14  
ZavaKid 写道
图是用什么东东画的呀?


直接用google docs做的,xls导入数据然后直接生成图片。 https://docs.google.com/

ps : 用普通的xls也可以完成这样的图标。

1 楼 ZavaKid 2011-01-28  
图是用什么东东画的呀?

相关推荐

    protobuf序列化和反序列化技术

    谷歌推出的Protocol Buffers(简称protobuf)是一种语言无关、平台无关的数据序列化协议,它能将结构化的数据序列化成字节流,方便在网络中进行高效、可靠的传输,同时也能将这些字节流还原为原来的结构化数据,即反...

    java序列化之protobuf

    Protocol Buffers(protobuf)是Google推出的一种高效、跨平台的数据序列化协议,它可以替代XML、JSON等传统序列化方式,提供更小、更快、更简单的解决方案。 protobuf的工作原理是定义一种结构化的数据格式,即....

    高性能序列化协议protobuf及源码分析.pptx

    高性能序列化协议protobuf及源码分析 分享仅供非商业用途,请于24小时内删除!如有侵权请联系本人删除

    自己实现的protobuf 压缩类,并能序列化反序列化

    protobuf是一种高效的数据序列化协议,它允许开发者将结构化的数据转换为二进制流,以便在网络传输或存储时占用更少的空间。这个压缩类可能是为了在处理protobuf数据时进一步优化存储效率,通过压缩技术减少数据体积...

    Unity 中使用Protobuf进行序列化和反序列化的Demo

    Protocol Buffers(Protobuf)是一种高效、跨平台的数据序列化协议,由Google开发。本Demo将展示如何在Unity中集成并使用Protobuf进行数据的序列化和反序列化操作。 首先,你需要了解什么是序列化和反序列化。序列...

    protobuf常用序列化和反序列化API

    protobuf(Protocol Buffers)是Google开发的一种数据序列化协议,广泛应用于网络通信、数据存储等领域。它提供了一种高效、灵活且跨平台的方式来编码和解码结构化数据。protobuf的核心在于定义消息类型(.proto文件...

    序列化工具(Gson, Jackson, FastJson, ProtoBuf)

    ProtoBuf是Google开发的一种数据序列化协议,可以将结构化数据序列化为二进制格式,以便于存储和网络传输。相比于JSON和XML,ProtoBuf的数据体积更小,解析速度更快。`proto.exe`是ProtoBuf的编译器,它可以将....

    C#中使用二进制和ProtoBuf分别进行序列化、反序列化、压缩、解压缩对比测试示例源码.zip

    ProtoBuf是一种高效的、跨平台的数据序列化协议,由Google开发,广泛应用于网络通信和数据存储。 首先,让我们深入了解一下二进制序列化。C#中的`System.Runtime.Serialization.Formatters.Binary.BinaryFormatter`...

    Unity 反序列化工具Protobuf

    [ProtoContract] //声明这个类能被序列化 public class UserData { //声明每一个需要被序列化的成员,编号从1开始 [ProtoMember(1)] public int id; [ProtoMember(2)] public string name; [ProtoMember...

    protobuf-2.5.0 JDK1.6JAVA编译 测试DEMO

    Protocol Buffers是Google开发的一种数据序列化协议,它允许开发者定义数据结构,然后生成相应的代码,以便在各种数据流中高效地存储和传输这些数据。 首先,我们来理解一下Protocol Buffers的基本概念。protobuf是...

    一个栗子-序列化工具protobuf

    protobuf是由Google开发的一种高效的数据序列化框架,它允许开发者定义数据结构,然后生成能够在各种语言中使用的代码,便于数据的存储和传输。 在描述中同样提到了protobuf,暗示我们将探讨的是关于如何使用...

    Python调用序列化数据工具Protocol Buffers——protobuf

    Protocol Buffers是Google开发的一种高效的数据序列化协议,它允许开发者将结构化的数据串行化,可用于数据存储、通信协议等方面。Python作为一门广泛使用的编程语言,可以方便地集成protobuf进行数据交换。在本文中...

    protobuf 序列化工具类

    protobuf,全称Protocol Buffers,是Google开发的一种数据序列化协议,用于高效地存储和传输结构化数据。它提供了一种语言无关、平台无关、高效且自动化的数据序列化方式,广泛应用于网络通信、数据库存储、配置文件...

    Google Protobuf基于Qt开发序列化与反序列化用QUdpSocket传输并显示。实例。

    Google Protobuf基于Qt开发序列化与反序列化用QUdpSocket传输并显示。实例。 具体可查看了解:https://blog.csdn.net/automoblie0/article/details/101363526

    ProtoBuf的介绍以及在Java中使用protobuf将对象进行序列化与反序列化示例代码.rar

    ProtoBuf(Protocol Buffers)是Google推出的一种数据序列化协议,它能够将结构化的数据序列化,可用于数据存储、通信协议等方面。ProtoBuf的优势在于它提供了高效、紧凑的二进制编码方式,相比XML或JSON等文本格式...

    在Unity5中Protobuf的序列化和反序列化

    Protocol Buffers是Google推出的一种高效的数据序列化协议,它提供了一种语言无关、平台无关的二进制数据表示方式。相比于XML或JSON等文本格式,Protobuf在传输效率和存储空间上有着显著优势,更适合于网络游戏和...

Global site tag (gtag.js) - Google Analytics