序列化方案
- Json
- protobuf
- JDK Serializable
测试方法
String line = "{很复杂的json,需要保密}";
DataStructure d = json.fromJson(line, DataStructure.class);
long time = System.currentTimeMillis();
long size = 0;
for(int i = 0;i< 1000000; i++){
d.setCostTime(i);
String b = json.toJson(d);
size = size + b.getBytes().length;
}
System.out.println("time :" + (System.currentTimeMillis() - time) +",and size:" + size);
测试结果
- 序列化:
方式 | 耗时(毫秒) | 结构化存储数据大小(byte) |
---|---|---|
json | 8954 | 777888890 |
protobuf2 | 5255 | 517983488 |
protobuf3 | 3247 | 357983488 |
jdk | 7281 | 1067000000 |
* 反序列化:
方式 | 耗时(毫秒) |
---|---|
json | 5107 |
protobuf2 | 4082 |
protobuf3 | 3123 |
jdk | 22779 |
插曲
测试过程种出现过一次异常:
序列化:
方式 | 耗时(毫秒) | 结构化存储数据大小(byte) |
---|---|---|
protobuf2 | 28653 | 517983488 |
protobuf3 | 25878 | 357983488 |
反序列化:
方式 | 耗时(毫秒) |
---|---|
protobuf3 | 22779 |
经查,由于在Java Object 转 pb Object 过程中,使用了反射
Class<? extends DataStructure> clazz = DataStructure.class;
Field[] fields = clazz.getDeclaredFields();
for(Field field : fields){
String name = field.getName();
String up = captureName(name);
if(field.getAnnotation(SerializableTag.class) != null)
//填入数据
}
这段代码导致速度下降了6~8倍
总结
- protobuf 性能全面优于 Json,速度加快大概在30%~40% 左右,存储数据量下降30%+
- 由于项目中的 Java Object 带Map属性在使用支持Map的 protobuf 3.0 时,性能还能有大幅提升 (目前spark 只支持2.5 Map 使用jdk序列化,再以byte方式序列化到pb)
- 线上环境全面使用 set,get 方法替代反射注入,提升性能(不要怕麻烦)。