一、msgpack序列化协议简介
什么是msgPack
msgpack对于数字字符和数字做了一定的优化,比如说上面这个例子,如果用JSON来表示的话就需要27个字节,而使用msgpack仅仅需要18个字节。这是因为JSON为了描述这个数据结构使用了一些不重要的字符(如大括号,双引号,冒号)来描述。而在msgpack中,我们可以看到,A7中的A用于描述该字段是一个string,7代表这个str是一个7个字节长度的string
msgpack对于数据的表示
- 简单的数据结构(如 bool)
2. 不需要表示长度的(如 float, int)
- 需要表示长度的(如 str, bin)
- 高级结构 (map, array)
二、关于msppack序列化增减字段的处理 jsf默认的是MsgPack序列化方式,接口字段里增减字段如何处理?
Msgpack是按字段顺序进行序列化和反序列化的,优点是速度快,缺点是无法改变字段顺序。因此,在两边不同时升级的情况下,字段兼容规则如下:(包括Bean和枚举)
1) 不要调整原有字段顺序,不能删减字段,除非是删最后一个字段。
2) 新加的字段必须在字段最后面(只是字段顺序,不是文件最后面,getter/setter方法等随意)。
3) 父类的字段不能变。因为父类一变相当于子类的中间插入一个字段。
满足上面规则,服务端和客户端哪边先升级都无所谓。
4)如果是需要父类加字段,或者中间加减字段这种,则需要服务端和调用端同时升级。
三、hessian序列化协议简介
四、hessian和msgpack序列化方式区别 1) Hessian序列化的时候,会写入字段名称,然后字段值,可以想象为一个map。
2) MsgPack序列化的时候,不写入字段名字,会按字段顺序写入值,可以想象为一个数组。
从这里可以看出:
1) Hessian产生的数据包较大,MsgPack产生的数据包较小。网络传输数据更小。
2) 序列化中Hessian的性能较差,(相当于每次map按名字取值),MsgPack性能更佳,(相当于数组取值)压测结果不同场景显示提高10% - 30%。(从数组取值比map取值高效)
3) Hessian的扩展性更好,上下兼容时,可以随意添加字段位置(相当于map可以随便赋值);MsgPack的性能更佳,但是上下兼容时,需要保证字段顺序(包括枚举顺序)。
4) 还包括其它一些差异:
例如:Hessian对Map/List等集合的支持就是全变成最普通的Hashmap或者ArrayList,一些指定的类型会丢失(例如LinkedHashMap–>HashMap),但是支持一些匿名的Map/List等集合类;
而MsgPack会保留集合类的类型(例如LinkedHashMap),但是不支持一些匿名集合类(例如List.subList(),Map.keySet(),Collections.emptyList(),Guava的匿名集合类,数据库查询结果直接返回的list等)。
五、其他常见序列化方式 protobuf
六、附录 msgpack format对照表
public static byte[] msgpackSerialization(T t) { MessagePack messagePack = new MessagePack(); byte[] write = new byte[0]; try { write = messagePack.write(t); } catch (IOException e) { e.printStackTrace(); } return write; }
public static byte[] hessianSerialization(T t) { byte[] data = null; try { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); Hessian2Output output = new Hessian2Output(outputStream); output.writeObject(t); output.getBytesOutputStream().flush(); output.completeMessage(); output.close(); data = outputStream.toByteArray(); } catch (IOException e) { e.printStackTrace(); } return data; }
public static byte[] jdkSerialization(T t) { byte[] data = null; try { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ObjectOutputStream output = new ObjectOutputStream(outputStream); output.writeObject(t); output.flush(); output.close(); data = outputStream.toByteArray(); } catch (IOException e) { e.printStackTrace(); } return data; }
public static void main(String[] args) {
UserInfo userInfo = new UserInfo();
userInfo.setUserId(0L);
userInfo.setBizUserPin("123");
userInfo.setTenantId("123");
userInfo.setShopId(0L);
userInfo.setMerchantId(0L);
byte[] hessianBytes = hessianSerialization(userInfo);
byte[] jdkBytes = jdkSerialization(userInfo);
byte[] msgPackBytes = msgpackSerialization(userInfo);
System.out.println("jdk序列化长度:" + jdkBytes.length);
System.out.println("msgpack序列化长度:" +msgPackBytes.length);
System.out.println("hessian序列化长度:" +hessianBytes.length);
System.out.println();
} 结果:
jdk序列化长度:272
msgpack序列化长度:12
hessian序列化长度:107