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

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

 

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

 

测试纬度

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

测试代码

准备protobuf文件

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

1.import "EnumType.proto";
2.
3.package demo;
4.option java_package = "com.agapple.protobuf.data";
5.option java_outer_classname = "InnerMessageProtos";
6.
7.message InnerMessage {
8.    optional string name = 1 [default = "name"];
9.    optional int32 id = 2;
10.    optional EnumType type = 3 [default = UNIVERSAL];
11.}

1.package demo;
2.option java_package = "com.agapple.protobuf.data";
3.option java_outer_classname = "EnumTypeProtos";
4.
5.enum EnumType {
6.    UNIVERSAL = 0;
7.    WEB = 1;
8.    IMAGES = 2;
9.    LOCAL = 3;
10.    NEWS = 4;
11.    PRODUCTS = 5;
12.    VIDEO = 6;
13.}

基本上把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

1.cd /home/ljh/work/code/src/main/java
2.
3./home/ljh/work/protobuf/bin/protoc --proto_path=com/agapple/protobuf/ --java_out=. com/agapple/protobuf/EnumType.proto
4./home/ljh/work/protobuf/bin/protoc --proto_path=com/agapple/protobuf/ --java_out=. com/agapple/protobuf/InnerMessage.proto
5./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代码

1.private static MessageProtos.Message getProtobufBean() {
2.        com.agapple.protobuf.data.MessageProtos.Message.Builder messageBuilder = MessageProtos.Message.newBuilder();
3.
4.        messageBuilder.setStrObj("message");
5.        messageBuilder.setFolatObj(1f);
6.        messageBuilder.addDoubleObj(1d);
7.        messageBuilder.addDoubleObj(2d);
8.        messageBuilder.setBoolObj(true);
9.
10.        messageBuilder.setBytesObj(ByteString.copyFrom(new byte[] { 1, 2, 3 }));
11.        messageBuilder.setInt32Obj(32);
12.        messageBuilder.setInt64Obj(64l);
13.        messageBuilder.setSint32Obj(232);
14.        messageBuilder.setSint64Obj(264);
15.        messageBuilder.setFixed32Obj(532);
16.        messageBuilder.setFixed64Obj(564);
17.        messageBuilder.setSfixed32Obj(2532);
18.        messageBuilder.setSfixed64Obj(2564);
19.        messageBuilder.setUint32Obj(632);
20.        messageBuilder.setUint64Obj(664);
21.
22.        com.agapple.protobuf.data.InnerMessageProtos.InnerMessage.Builder innerMessageBuilder = InnerMessageProtos.InnerMessage.newBuilder();
23.        innerMessageBuilder.setId(1);
24.        innerMessageBuilder.setName("inner");
25.        innerMessageBuilder.setType(EnumType.PRODUCTS);
26.
27.        messageBuilder.setInnerMessage(innerMessageBuilder);
28.
29.        return messageBuilder.build();
30.    }

准备纯Pojo Bean 

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

属性和proto的bean保持一致。

 

构建bean对象

1.private static MessagePojo getPojoBean() {
2.        MessagePojo bean = new MessagePojo();
3.
4.        bean.setStrObj("message");
5.        bean.setFolatObj(1f);
6.        List<Double> doubleObj = new ArrayList<Double>();
7.        doubleObj.add(1d);
8.        doubleObj.add(2d);
9.        bean.setDoubleObj(doubleObj);
10.        bean.setBoolObj(true);
11.
12.        bean.setBytesObj(new byte[] { 1, 2, 3 });
13.        bean.setInt32Obj(32);
14.        bean.setInt64Obj(64l);
15.        bean.setSint32Obj(232);
16.        bean.setSint64Obj(264);
17.        bean.setFixed32Obj(532);
18.        bean.setFixed64Obj(564);
19.        bean.setSfixed32Obj(2532);
20.        bean.setSfixed64Obj(2564);
21.        bean.setUint32Obj(632);
22.        bean.setUint64Obj(664);
23.
24.        InnerMessagePojo innerMessagePojo = new InnerMessagePojo();
25.        innerMessagePojo.setId(1);
26.        innerMessagePojo.setName("inner");
27.        innerMessagePojo.setType(EnumTypePojo.PRODUCTS);
28.
29.        bean.setInnerMessage(innerMessagePojo);
30.
31.        return bean;
32.    }

具体的测试代码

定义测试Template接口

1.interface TestCallback {
2.
3.    String getName();
4.
5.    byte[] writeObject(Object source);
6.
7.    Object readObject(byte[] bytes);
8.}

统一的测试模板

1.private static void testTemplate(TestCallback callback, Object source, int count) {
2.        int warmup = 10;
3.        // 先进行预热,加载一些类,避免影响测试
4.        for (int i = 0; i < warmup; i++) {
5.            byte[] bytes = callback.writeObject(source);
6.            callback.readObject(bytes);
7.        }
8.        restoreJvm(); // 进行GC回收
9.        // 进行测试
10.        long start = System.nanoTime();
11.        long size = 0l;
12.        for (int i = 0; i < count; i++) {
13.            byte[] bytes = callback.writeObject(source);
14.            size = size + bytes.length;
15.            callback.readObject(bytes);
16.            // System.out.println(callback.readObject(bytes));
17.            bytes = null;
18.        }
19.        long nscost = (System.nanoTime() - start);
20.        System.out.println(callback.getName() + " total cost=" + integerFormat.format(nscost) + "ns , each cost="
21.                           + integerFormat.format(nscost / count) + "ns , and byte sizes = " + size / count);
22.        restoreJvm();// 进行GC回收
23.
24.    }

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

 

  相应的restoreJvm方法: 

1.private static void restoreJvm() {
2.        int maxRestoreJvmLoops = 10;
3.        long memUsedPrev = memoryUsed();
4.        for (int i = 0; i < maxRestoreJvmLoops; i++) {
5.            System.runFinalization();
6.            System.gc();
7.
8.            long memUsedNow = memoryUsed();
9.            // break early if have no more finalization and get constant mem used
10.            if ((ManagementFactory.getMemoryMXBean().getObjectPendingFinalizationCount() == 0)
11.                && (memUsedNow >= memUsedPrev)) {
12.                break;
13.            } else {
14.                memUsedPrev = memUsedNow;
15.            }
16.        }
17.    }
18.
19.    private static long memoryUsed() {
20.        Runtime rt = Runtime.getRuntime();
21.        return rt.totalMemory() - rt.freeMemory();
22.    }

最后相应的测试例子:

1.final int testCount = 1000 * 500;
2.final MessageProtos.Message protoObj = getProtobufBean();
3.final MessagePojo pojoOBj = getPojoBean();
4.
5.// Serializable测试
6.testTemplate(new TestCallback() {
7.
8.    public String getName() {
9.        return "Serializable Test";
10.    }
11.
12.    @Override
13.    public byte[] writeObject(Object source) {
14.        try {
15.            ByteArrayOutputStream bout = new ByteArrayOutputStream();
16.            ObjectOutputStream output = new ObjectOutputStream(bout);
17.            output.writeObject(source);
18.            return bout.toByteArray();
19.        } catch (IOException e) {
20.            e.printStackTrace();
21.        }
22.        return null;
23.    }
24.
25.    @Override
26.    public Object readObject(byte[] bytes) {
27.        try {
28.            ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
29.            ObjectInputStream input = new ObjectInputStream(bin);
30.            return input.readObject();
31.        } catch (Exception e) {
32.            e.printStackTrace();
33.        }
34.        return null;
35.    }
36.}, pojoOBj, testCount);
37.
38.// protobuf测试
39.testTemplate(new TestCallback() {
40.
41.    public String getName() {
42.        return "protobuf test";
43.    }
44.
45.    @Override
46.    public byte[] writeObject(Object source) {
47.        if (source instanceof MessageProtos.Message) {
48.            MessageProtos.Message message = (MessageProtos.Message) source;
49.            return message.toByteArray();
50.        }
51.
52.        return null;
53.    }
54.
55.    @Override
56.    public Object readObject(byte[] bytes) {
57.        try {
58.            return MessageProtos.Message.parseFrom(bytes);
59.        } catch (InvalidProtocolBufferException e) {
60.            e.printStackTrace();
61.        }
62.        return null;
63.    }
64.}, protoObj, testCount);
65.
66.// json测试
67.final ObjectMapper objectMapper = new ObjectMapper();
68.final JavaType javaType = TypeFactory.type(pojoOBj.getClass());
69.
70.// JSON configuration not to serialize null field
71.objectMapper.getSerializationConfig().setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
72.
73.// JSON configuration not to throw exception on empty bean class
74.objectMapper.getSerializationConfig().disable(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS);
75.
76.// JSON configuration for compatibility
77.objectMapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
78.objectMapper.configure(Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
79.
80.testTemplate(new TestCallback() {
81.
82.    public String getName() {
83.        return "Jackson Test";
84.    }
85.
86.    @Override
87.    public byte[] writeObject(Object source) {
88.        try {
89.            return objectMapper.writeValueAsBytes(source);
90.        } catch (JsonGenerationException e) {
91.            e.printStackTrace();
92.        } catch (JsonMappingException e) {
93.            e.printStackTrace();
94.        } catch (IOException e) {
95.            e.printStackTrace();
96.        }
97.
98.        return null;
99.    }
100.
101.    @Override
102.    public Object readObject(byte[] bytes) {
103.        try {
104.            return objectMapper.readValue(bytes, 0, bytes.length, javaType);
105.        } catch (JsonParseException e) {
106.            e.printStackTrace();
107.        } catch (JsonMappingException e) {
108.            e.printStackTrace();
109.        } catch (IOException e) {
110.            e.printStackTrace();
111.        }
112.        return null;
113.    }
114.}, pojoOBj, testCount);
115.
116.// Xstream测试
117.final XStream xstream = new XStream();
118.testTemplate(new TestCallback() {
119.
120.    public String getName() {
121.        return "Xstream test";
122.    }
123.
124.    @Override
125.    public byte[] writeObject(Object source) {
126.        return xstream.toXML(source).getBytes();
127.    }
128.
129.    @Override
130.    public Object readObject(byte[] bytes) {
131.        return xstream.fromXML(new ByteArrayInputStream(bytes));
132.    }
133.}, pojoOBj, testCount);

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

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

1.<dependency>
2.    <groupId>com.caucho</groupId>
3.    <artifactId>hessian</artifactId>
4.    <version>3.1.5</version>
5.</dependency>

测试了3种情况:

 

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

 

 

测试代码:

1.// hessian 2 with no deflat
2.        testTemplate(new TestCallback() {
3.
4.            public String getName() {
5.                return "hessian 2 with no deflat";
6.            }
7.
8.            @Override
9.            public byte[] writeObject(Object source) {
10.                try {
11.                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
12.                    Hessian2Output out = new Hessian2Output(bos);
13.                    // out.startMessage();
14.                    out.writeObject(source);
15.                    // out.completeMessage();
16.                    out.flush();
17.                    return bos.toByteArray();
18.                } catch (IOException e) {
19.                    e.printStackTrace();
20.                }
21.                return null;
22.            }
23.
24.            @Override
25.            public Object readObject(byte[] bytes) {
26.                try {
27.                    ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
28.                    Hessian2Input in = new Hessian2Input(bin);
29.                    // in.startMessage();
30.                    Object obj = in.readObject();
31.                    // in.completeMessage();
32.                    return obj;
33.                } catch (IOException e) {
34.                    e.printStackTrace();
35.                }
36.                return null;
37.            }
38.        }, pojoOBj, testCount);
39.
40.        // hessian 2 with deflat
41.        final Deflation envelope = new Deflation();
42.        testTemplate(new TestCallback() {
43.
44.            public String getName() {
45.                return "hessian 2 with deflat";
46.            }
47.
48.            @Override
49.            public byte[] writeObject(Object source) {
50.                try {
51.                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
52.                    Hessian2Output out = new Hessian2Output(bos);
53.                    out = envelope.wrap(out);
54.                    out.writeObject(source);
55.                    out.flush();
56.                    out.close(); // 记得关闭
57.                    return bos.toByteArray();
58.                } catch (Exception e) {
59.                    e.printStackTrace();
60.                }
61.                return null;
62.            }
63.
64.            @Override
65.            public Object readObject(byte[] bytes) {
66.                try {
67.                    ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
68.                    Hessian2Input in = new Hessian2Input(bin);
69.                    in = envelope.unwrap(in);
70.                    Object obj = in.readObject();
71.                    in.close();
72.                    return obj;
73.                } catch (IOException e) {
74.                    e.printStackTrace();
75.                }
76.                return null;
77.            }
78.        }, pojoOBj, testCount);
79.
80.        // hessian 1 with no deflat
81.        testTemplate(new TestCallback() {
82.
83.            public String getName() {
84.                return "hessian 1 with no deflat";
85.            }
86.
87.            @Override
88.            public byte[] writeObject(Object source) {
89.                try {
90.                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
91.                    HessianOutput out = new HessianOutput(bos);
92.                    out.writeObject(source);
93.                    out.flush();
94.                    return bos.toByteArray();
95.                } catch (Exception e) {
96.                    e.printStackTrace();
97.                }
98.                return null;
99.            }
100.
101.            @Override
102.            public Object readObject(byte[] bytes) {
103.                try {
104.                    ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
105.                    HessianInput in = new HessianInput(bin);
106.                    Object obj = in.readObject();
107.                    in.close();
108.                    return obj;
109.                } catch (IOException e) {
110.                    e.printStackTrace();
111.                }
112.                return null;
113.            }
114.        }, 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

时间: 2024-10-31 08:00:31

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

Win2000服务器两种终端协议的比较

前言: WIN2000服务器有两种终端协议,一种是系统自带的RDP协议,一种是第三方协议,美国CTRIX公司的ICA协议.笔者首先使用的是RDP协议,在一些低档586微机.WIN95(98)平台下,实现Win2000服务器的终端功能.后来通过Win2000终端卡的使用,逐渐了解和掌握了ICA协议的使用,在Dos.Win95(98)平台及386.486.586微机条件下,实现了Win2000服务器的终端方式.下面从几个方面对两种协议进行比较. 一.终端的实现方式 1.RDP协议只能在WIN3.1.

Java程序员需要了解的五种开源协议

五种开源协议的比较(BSD,Apache,GPL,LGPL,MIT). 当Adobe.Microsoft.Sun等一系列巨头开始表现出对"开源"的青睐时,"开源"的时代即将到来! 现今存在的开源协议很多,而经过Open Source Initiative组织通过批准的开源协议目前有58种(http://www.opensource.org/licenses/alphabetical).我们在常见的开源协议如BSD, GPL, LGPL,MIT等都是OSI批准的协议.

PHP5.5四种序列化性能对比

json_encode,serialize,igbinary,msgpack四种序列化方式,在之前已经有过相关的测试,PHP5.5这方面的测试暂时没有,这次测试基于PHP5.5,并且测试用例,http://blog.csdn.net/hguisu/article/details/7651730的测试用例是一样的,只是从这个测试上家里igbinary serialize的测试,作为对比,可以参考http://www.ooso.net/archives/538 运行环境        PHP5.5

十五天精通WCF——第十二天 说说wcf中的那几种序列化

原文:十五天精通WCF--第十二天 说说wcf中的那几种序列化 我们都知道wcf是由信道栈组成的,在我们传输的参数走到传输信道层之前,先需要经过序列化的过程,也就是将参数序列化为message,这篇 我们就来说说这里的序列化,蛮有意思的,可能初学者也明白,在wcf中默认的序列化是DataContractSerializer,确实是这样,不过wcf在信道中 其实不仅仅支持DataContractSerializer,它还支持其他类型的序列化,比如XmlSerializer,NetDataContr

谈谈分布式事务之四: 两种事务处理协议OleTx与WS-AT

在年前写一个几篇关于分布式事务的文章,实际上这些都是为了系统介绍WCF事务处理体系而提供的相关的背景和基础知识.今天发最后一篇,介绍分布式事务采用的两种协议,即OleTx和WS-AT,内容比较枯燥,但对于后续对WCF事务处理框架进行深入剖析的系列文章来说,确是不可以缺少的.总的来说,基于WCF的分布式事务采用的是两阶段提交(2PC:Two Phase Commit)协议.具体来说,我们可以选择如下两种事务处理协议实现WCF的分布式式事务,它们按照各自的方式提供了对两阶段提交的实现. OleTx:

Spearal —— 超越 JSON 全新的对象序列化协议

Spearal 是一个全新的开源的序列化协议,旨在突破 JSON 的限制,其目标第一步是让 HTML 和原生移动应用可连接到 Java 的后端. Spearal 主要目标是让序列化更简单,封装了端点之间复杂的数据库结构交换.提供包括部分对象序列化.内建 JPA 支持.发散模式.对象属性过滤等等.目前该项目还在早期开发阶段. 文章转载自 开源中国社区 [http://www.oschina.net]

常见的几种开源协议

        在学习中经常能看到一些词,例如:GPL,LGPL等等,自打上学那会就遇见过,对它们的具体含义却不了解,今天给它们总结一下.         说到开源协议,不得不提GNU.课本上给的定义是"GNU is Not Unix",这是官方给出的递归定义,永远也找不到本意,我们可以将它理解为一个自由软件工程项目或者一种计划,是由Richard Stallman在1983年9月27公开发起的,它的目标是创建一套完全自由.开放的操作系统.1985年10月Richard Stallma

一种c#深拷贝方式完胜java深拷贝(实现上的对比分析)_C#教程

楼主是一名asp.net攻城狮,最近经常跑java组客串帮忙开发,所以最近对java的一些基础知识特别上心.却遇到需要将一个对象深拷贝出来做其他事情,而原对象保持原有状态的情况.(实在是不想自己new一个出来,然后对着一堆字段赋值......好吧,再此之前我没有关心是否项目框架有深拷贝的方法),然后就想着用反射实现吧....接下来 是我自己的原因,还是真的不存在这样的纯用反射实现的深拷贝方式....(c#是有纯反射实现的) 但也不能算自己白忙活吧,也找到了其他实现深拷贝的方式(但是每种方式我都觉

java 使用http协议访问api接口,发送json数据

问题描述 java 使用http协议访问api接口,发送json数据 http访问 api接口,http的头需要加入id 和密钥进行验证,发送json格式的数据给应用程序,求大神指教.有没有实例程序可供参考的,谢谢各位了 解决方案 jsp服务器端 变量 = request.getHeader(""http头字段""); 客户端 HashMap<String String> headers = new HashMap<String String>