MessagePack简析 您所在的位置:网站首页 map_movies是什么文件 MessagePack简析

MessagePack简析

2023-10-12 12:16| 来源: 网络整理| 查看: 265

一、MessagePack是什么

先看官方的定义:MessagePack是一种高效的二进制序列化格式。它允许您像JSON一样在多个语言之间交换数据。但是,它更快并且更小。

 

从官方定义中,可以有如下的结论:

MessagePack是一个二进制序列化格式,因而它序列化的结果可以在多个语言间进行数据的交换。

从性能上讲,它要比json的序列化格式要好。

从结果大小上讲,它要比json的序列化结果要小。

 

但是官方并没有提MessagePack和google pb的对比,实际上从空间和时间两个方面对比,pb均要优于MessagePack,但pb相对MessagePack 的缺点是支持的语言种类比较少,需要编写专门的 .proto文件,使用上没有MessagePack方便。

 

二、MessagePack的主要概念   2.1 type system 类型体系是MessagePack的基础,也是MessagePack在序列化后比json占用空间小的关键。当前包含的type有如下几类: Integer represents an integer Nil represents nil Boolean represents true or false Float represents a IEEE 754 double precision floating point number including NaN and Infinity Raw String extending Raw type represents a UTF-8 string Binary extending Raw type represents a byte array Array represents a sequence of objects Map represents key-value pairs of objects Extension represents a tuple of type information and a byte array where type information is an integer whose meaning is defined by applications or MessagePack specification Timestamp represents an instantaneous point on the time-line in the world that is independent from time zones or calendars. Maximum precision is nanoseconds.   这个类型体系将我们在代码开发中用到的数据格式进行了映射,并且通过Extension这个类型给使用者留出了自由扩充的空间,但由于表示形式的限制,当前Extension最多有127个。   每一种类型能够表示的范围可以查看MessagePack规范中的Limitation部分和Extension types部分。   2.2 formats 在MessagePack中一个value的组成格式是这样的:类型[长度][data]。下面列出几个示例,详细完整的描述请看附录中的MessagePack规范。   2.2.1常量型 比如对于null、true、false这三个值,在MessagePack会被固定的映射为如下的值。 format name first byte (in binary) first byte (in hex) nil 11000000 0xc0 false 11000010 0xc2 true 11000011 0xc3 2.2.2 int型(包含有符号整数和无符号整数)   示例如下   0xcc表示当前的值的类型是无符号整数并且长度不超过8个bit,具体的值内容需要通过后续8个bit位的内容来计算 0xcd表示当前的值的类型是无符号整数并且长度不超过16个bit,具体的值内容需要通过后续16个bit位的内容来计算 0xd0表示当前的值的类型是有符号整数并且长度不超过8个bit,具体的值内容需要通过后续8个bit位的内容来计算 0xd1表示当前的值的类型是有符号整数并且长度不超过16个bit,具体的值内容需要通过后续16个bit位的内容来计算   uint 8 stores a 8-bit unsigned integer +--------+--------+ | 0xcc |ZZZZZZZZ| +--------+--------+ uint 16 stores a 16-bit big-endian unsigned integer +--------+--------+--------+ | 0xcd |ZZZZZZZZ|ZZZZZZZZ| +--------+--------+--------+ int 8 stores a 8-bit signed integer +--------+--------+ | 0xd0 |ZZZZZZZZ| +--------+--------+ int 16 stores a 16-bit big-endian signed integer +--------+--------+--------+ | 0xd1 |ZZZZZZZZ|ZZZZZZZZ| +--------+--------+--------+

 

2.2.3 字符串   0xd9表示当前的值的类型是字符串并且长度不超过(2^8)-1个bytes ,具体的长度需要通过后续8个bit位的内容来计算,字符串的具体内容是后续长度的byte所表示的内容 0xda表示当前的值的类型是字符串并且长度不超过(2^16)-1个bytes ,具体的长度需要通过后续16个bit位的内容来计算,字符串的具体内容是后续长度的byte所表示的内容   str 8 stores a byte array whose length is upto (2^8)-1 bytes: +--------+--------+========+ | 0xd9 |YYYYYYYY| data | +--------+--------+========+ str 16 stores a byte array whose length is upto (2^16)-1 bytes: +--------+--------+--------+========+ | 0xda |ZZZZZZZZ|ZZZZZZZZ| data | +--------+--------+--------+========+

  

2.2.4 数组   0xdc表示当前的值的类型是数组并且长度不超过(2^16)-1个元素 ,具体的长度需要通过后续16个bit位(两个byte)的内容来计算,计算出来的值就是数组元素的个数 0xdd表示当前的值的类型是数组并且长度不超过(2^32)-1个元素 ,具体的长度需要通过后续32个bit位(4个byte)的内容来计算,计算出来的值就是数组元素的个数   array 16 stores an array whose length is upto (2^16)-1 elements: +--------+--------+--------+~~~~~~~~~~~~~~~~~+ | 0xdc |YYYYYYYY|YYYYYYYY| N objects | +--------+--------+--------+~~~~~~~~~~~~~~~~~+ array 32 stores an array whose length is upto (2^32)-1 elements: +--------+--------+--------+--------+--------+~~~~~~~~~~~~~~~~~+ | 0xdd |ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ|ZZZZZZZZ| N objects | +--------+--------+--------+--------+--------+~~~~~~~~~~~~~~~~~+

  

  2.2.5 小结       2.3 Serialization:type to format conversion   source types output format Integer int format family (positive fixint, negative fixint, int 8/16/32/64 or uint 8/16/32/64) Nil nil Boolean bool format family (false or true) Float float format family (float 32/64) String str format family (fixstr or str 8/16/32) Binary bin format family (bin 8/16/32) Array array format family (fixarray or array 16/32) Map map format family (fixmap or map 16/32) Extension ext format family (fixext or ext 8/16/32)

 

If an object can be represented in multiple possible output formats, serializers SHOULD use the format which represents the data in the smallest number of bytes.   2.4 Deserialization: format to type conversion source formats output type positive fixint, negative fixint, int 8/16/32/64 and uint 8/16/32/64 Integer nil Nil false and true Boolean float 32/64 Float fixstr and str 8/16/32 String bin 8/16/32 Binary fixarray and array 16/32 Array fixmap map 16/32 Map fixext and ext 8/16/32 Extension   三、为什么MessagePack比json序列化使用的字节流更少   3.1 直观对比 可以通过下图的两张图简单进行下对比,第一张图是同一个数据类型的内容用json和messagepack序列化的结果。       从第二张图可以明显看到messagepack要比json占用的空间更少。   3.2 序列化结果只有value且value进行了专属映射   这张图是MessagePack官网上的,用来进行json和MessagePack序列化结果的对比,实际情况是否确实如此呢? 我本地使用的msgpack-0.6.12版本。 代码如下:   public class MessagePackSerializationCompareJson { @Message // Annotation public static class MyMessage { // public fields are serialized. public boolean compact; public int schema; public String toString() { return "compact:"+compact+";schema:"+schema; } } /** * * @param args * @throws IOException */ public static void main(String[] args) throws IOException { //初始化一个对象 MyMessage src = new MyMessage(); src.compact = true; src.schema=0; //利用MessagePack进行序列化 MessagePack msgpack = new MessagePack(); // Serialize byte[] bytes = msgpack.write(src); System.out.println("msgpack result length:"+bytes.length); //利用json进行序列化 String jsonResult = JSONObject.toJSON(src).toString(); System.out.println("json result length:"+jsonResult.getBytes().length); } }

  

  运行结果如下:   json result length:27 msgpack result length:3

  

  json序列化的结果是27,和官网图片中的结果相同。但MessagePack的序列化结果是3,要比官网中的数字小很多。 按照上面图片的解释应当是: 第一个byte是82,表示序列化后的结果有两个元素 第二个byte是c3,表示第一个元素的值是true 第三个byte是00,表示第二个元素的值是0   为了验证我们的推测,我们可以在MyMessage类中再添加一个boolean类型的属性,但不给这个属性赋值,按照java的规范,这个属性的值就是false,按照MessagePack的规范,就会被转为一个byte的c2,这样msgpack序列化后的长度值就是4.  而json序列化的增加值要增加不少,是属性名称的长度+5(false的长度)+4(要增加两个双引号,一个逗号,一个冒号),如果属性名称长度是4,则一共会增加13个byte,总长度就是40. public class MessagePackSerializationCompareJson { @Message // Annotation public static class MyMessage { // public fields are serialized. public boolean compact; public int schema; public boolean link; public String toString() { return "compact:"+compact+";schema:"+schema+";link:"+link; } } /** * * @param args * @throws IOException */ public static void main(String[] args) throws IOException { //初始化一个对象 MyMessage src = new MyMessage(); src.compact = true; src.schema=0; //利用json进行序列化 String jsonResult = JSONObject.toJSON(src).toString(); System.out.println("json result length:"+jsonResult.getBytes().length); //利用MessagePack进行序列化 MessagePack msgpack = new MessagePack(); // Serialize byte[] bytes = msgpack.write(src); System.out.println("msgpack result length:"+bytes.length); } }

  

  上面代码的执行的结果也符合猜测:   json result length:40 msgpack result length:4

  

  从这个数字上看,MessagePack明显优于json,特别是在属性多的情况下差距会更大。即使json中把key去掉,序列化后的结果也要比MessagePack占用的空间大。   3.2 序列化对象的属性顺序不能变动 3.1分析了MessagePack序列化的结果中只包含了value,而不包含key。因而在进行反序列化需要保证类中属性的顺序必须保证完全一致,否则就会出错: 如果两个属性的类型一致,可以反序列化,但是值发生错乱。 如果两个属性的类型不一致,会抛出类型不匹配异常。   3.2.1 顺序不同,类型相同   public class SimpleMessagePackPractice { @Message // Annotation public static class MyMessage { // public fields are serialized. public boolean compact; public boolean link; public String toString() { return "link:" + link + ";compact:" + compact; } } @Message // Annotation public static class MyMessage2 { // public fields are serialized. public boolean link; public boolean compact; public String toString() { return "link:" + link + ";compact:" + compact; } } /** * * @param args * @throws IOException */ public static void main(String[] args) throws IOException { //初始化一个对象 MyMessage src = new MyMessage(); src.compact = true; src.link = false; //利用MessagePack进行序列化 MessagePack msgpack = new MessagePack(); // Serialize byte[] bytes = msgpack.write(src); //利用MessagePack进行反序列化 MyMessage2 dst = msgpack.read(bytes, MyMessage2.class); System.out.println("msgpack 原始数据:" + src); System.out.println("msgpack 反序列化:" + dst); } }

  

  上述代码的执行结果如下: msgpack 原始数据:link:false;compact:true msgpack 反序列化:link:true;compact:false   3.2.1 顺序不同,类型不同   public class SimpleMessagePackPractice { @Message // Annotation public static class MyMessage { // public fields are serialized. public boolean compact; public String link; public String toString() { return "link:" + link + ";compact:" + compact; } } @Message // Annotation public static class MyMessage2 { // public fields are serialized. public String link; public boolean compact; public String toString() { return "link:" + link + ";compact:" + compact; } } /** * * @param args * @throws IOException */ public static void main(String[] args) throws IOException { //初始化一个对象 MyMessage src = new MyMessage(); src.compact = true; src.link = "www.baidu.com"; //利用MessagePack进行序列化 MessagePack msgpack = new MessagePack(); // Serialize byte[] bytes = msgpack.write(src); //利用MessagePack进行反序列化 MyMessage2 dst = msgpack.read(bytes, MyMessage2.class); System.out.println("msgpack 原始数据:" + src); System.out.println("msgpack 反序列化:" + dst); } }

  

  执行结果:   Exception in thread "main" org.msgpack.MessageTypeException: Expected raw value, but got boolean at org.msgpack.unpacker.Accept.acceptBoolean(Accept.java:33) at org.msgpack.unpacker.MessagePackUnpacker.readOneWithoutStackLarge(MessagePackUnpacker.java:154) at org.msgpack.unpacker.MessagePackUnpacker.readOneWithoutStack(MessagePackUnpacker.java:139) at org.msgpack.unpacker.MessagePackUnpacker.readOne(MessagePackUnpacker.java:73) at org.msgpack.unpacker.MessagePackUnpacker.readString(MessagePackUnpacker.java:502) at org.msgpack.template.StringTemplate.read(StringTemplate.java:46) at org.msgpack.template.StringTemplate.read(StringTemplate.java:25) at org.msgpack.template.AbstractTemplate.read(AbstractTemplate.java:31) at com.my.msgpack.SimpleMessagePackPractice$MyMessage2_$$_Template_1305193908_1.read(SimpleMessagePackPractice$MyMessage2_$$_Template_1305193908_1.java) at org.msgpack.template.AbstractTemplate.read(AbstractTemplate.java:31) at org.msgpack.MessagePack.read(MessagePack.java:388) at org.msgpack.MessagePack.read(MessagePack.java:371) at com.my.msgpack.SimpleMessagePackPractice.main(SimpleMessagePackPractice.java:61)

  

  参考资料 MessagePack specification https://github.com/msgpack/msgpack/blob/master/spec.md#type-system https://www.jianshu.com/p/8c24bef40e2f http://jimmee.iteye.com/blog/2042420 http://blog.csdn.net/weiyuefei/article/details/52208186

 

 


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有