MessagePack简析
一、MessagePack是什么
先看官方的定义:MessagePack是一种高效的二进制序列化格式。它允许您像JSON一样在多个语言之间交换数据。但是,它更快并且更小。
从官方定义中,可以有如下的结论:
MessagePack是一个二进制序列化格式,因而它序列化的结果可以在多个语言间进行数据的交换。
从性能上讲,它要比json的序列化格式要好。
从结果大小上讲,它要比json的序列化结果要小。
但是官方并没有提MessagePack和google pb的对比,实际上从空间和时间两个方面对比,pb均要优于MessagePack,但pb相对MessagePack 的缺点是支持的语言种类比较少,需要编写专门的 .proto文件,使用上没有MessagePack方便。
二、MessagePack的主要概念
2.1 type system
- 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.
2.2 formats
2.2.1常量型
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)
|
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 直观对比
3.2 序列化结果只有value且value进行了专属映射
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
- 第一个byte是82,表示序列化后的结果有两个元素
- 第二个byte是c3,表示第一个元素的值是true
- 第三个byte是00,表示第二个元素的值是0
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
3.2 序列化对象的属性顺序不能变动
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
MessagePack简析的更多相关文章
- 简析.NET Core 以及与 .NET Framework的关系
简析.NET Core 以及与 .NET Framework的关系 一 .NET 的 Framework 们 二 .NET Core的到来 1. Runtime 2. Unified BCL 3. W ...
- 简析 .NET Core 构成体系
简析 .NET Core 构成体系 Roslyn 编译器 RyuJIT 编译器 CoreCLR & CoreRT CoreFX(.NET Core Libraries) .NET Core 代 ...
- RecycleView + CardView 控件简析
今天使用了V7包加入的RecycleView 和 CardView,写篇简析. 先上效果图: 原理图: 这是RecycleView的工作原理: 1.LayoutManager用来处理RecycleVi ...
- Java Android 注解(Annotation) 及几个常用开源项目注解原理简析
不少开源库(ButterKnife.Retrofit.ActiveAndroid等等)都用到了注解的方式来简化代码提高开发效率. 本文简单介绍下 Annotation 示例.概念及作用.分类.自定义. ...
- PHP的错误报错级别设置原理简析
原理简析 摘录php.ini文件的默认配置(php5.4): ; Common Values: ; E_ALL (Show all errors, warnings and notices inclu ...
- Android 启动过程简析
首先我们先来看android构架图: android系统是构建在linux系统上面的. 所以android设备启动经历3个过程. Boot Loader,Linux Kernel & Andr ...
- Android RecycleView + CardView 控件简析
今天使用了V7包加入的RecycleView 和 CardView,写篇简析. 先上效果图: 原理图: 这是RecycleView的工作原理: 1.LayoutManager用来处理RecycleVi ...
- Java Annotation 及几个常用开源项目注解原理简析
PDF 版: Java Annotation.pdf, PPT 版:Java Annotation.pptx, Keynote 版:Java Annotation.key 一.Annotation 示 ...
- 【ACM/ICPC2013】POJ基础图论题简析(一)
前言:昨天contest4的惨败经历让我懂得要想在ACM领域拿到好成绩,必须要真正的下苦功夫,不能再浪了!暑假还有一半,还有时间!今天找了POJ的分类题库,做了简单题目类型中的图论专题,还剩下二分图和 ...
随机推荐
- POJ 1422 Air Raid
题目链接: http://poj.org/problem?id=1422 Description Consider a town where all the streets are one-way a ...
- 阻止安卓实体返回键后退的网页js实现
提供两种解决方法吧,都是网上来的,侵权删,毕竟我等只是搞后端的-- 第一种方法: // 阻止安卓实体键后退 // 页面载入时使用pushState插入一条历史记录 history.pushState( ...
- CCF系列之有趣的数(201312-4)
题目链接: http://115.28.138.223:81/view.page?opid=4 试题名称: 有趣的数 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 我们把一个 ...
- redux学习日志:关于react-redux
首先先强调一句:一定要多读官方文档,而且要精读,否则你会忽略掉很多东西! 一,Provider 刚开始看的时候,大致浏览了一下,知道了这个组件是能够接收store作为它的属性,然后它里面的子组件就可以 ...
- python_求1-2+3-4+......-100的值
求1-2+3-4+5---100 = ? 逻辑整理: -- 本质上可以转换一下,1+3+5+--+99 -(2+4+--+100) 加减部分间隔都为2,先求1+3+5+--+99的值, 再求2+4+- ...
- linux各种顔色代表
@linux中的各文件的颜色表示什么 白色:表示普通文件 蓝色:表示目录 绿色:表示可执行文件 红色:表示压缩文件 浅蓝色:链接文件 红色闪烁:表示链接的文件有问题 黄色:表示设备文件 灰色:表示其它 ...
- Linux上常用软件安装和总结
Linux总结: 以前只顾着撸码,Linux这些一般都是运维玩的,然后也没怎么折腾过,每次上线也都只是发布下,最多也就是启停服务器.最近闲来无事就玩了玩Linux,还挺好的. 这里做一个总结来结束Li ...
- Linux安装JDK步骤
Linux安装JDK步骤 1.先从官网下载JDK安装包,我下载的是:jdk-8u131-linux-x64.tar.gz版本 2.在usr下创建java文件夹 # mkdir /usr/java 3. ...
- jspf与jsp的区别
如果想把一个jspf的文件引入(incurred)到一个jsp页面中,只能使用"@include"指令引入 如果使用<jsp:include>引入,jspf文件中的内容 ...
- Cacti在selinux开启的情况下使用
# chcon -R -t httpd_sys_content_t /var/www/html/cacti