記一次後臺儲存方案優化
阿新 • • 發佈:2019-02-13
序列化方案
- 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 方法替代反射注入,提升效能(不要怕麻煩)。