探险新型序列化工具MessagePack

淡淡的烟草味﹌ 2022-05-14 04:38 370阅读 0赞

MessagePack是最近一个比较热门与Json做比较的序列化工具,它的优点是相比于json,序列化速度更快和序列化之后的字节数组更小,正如它的官网https://msgpack.org/卖的广告所说

It’s like JSON.
but fast and small.

下面我们以三个方面来对MessagePack做一个初步的探险

一.What is MessagePack

1.以官网的阐述来表明:

MessagePack is an efficient binary serialization format. It lets you exchange data among multiple languages like JSON. But it’s faster and smaller. Small integers are encoded into a single byte, and typical short strings require only one extra byte in addition to the strings themselves.
中文翻译:
MessagePack是一种有效的二进制序列化格式。 它允许您在多种语言(如JSON)之间交换数据。 但它更快更小。 小整数被编码为单个字节,典型的短字符串除了字符串本身外只需要一个额外的字节。

可以看出它序列化出来能比json更小的原因是,整数会被编码成一个字节,另外json的字符串的冒号和引号也会被以一种特殊的方式进行压缩,下面的图片可以看出来MessagePack压缩之后的效果:
这里写图片描述
from:http://indiegamr.com/cut-your-data-exchange-traffic-by-up-to-50-with-one-line-of-code-msgpack-vs-json/

2.验证Message的序列化速度和内容是否更优于JSON
  1. package msgpack;
  2. import com.alibaba.fastjson.JSON;
  3. import com.fasterxml.jackson.databind.ObjectMapper;
  4. import org.msgpack.jackson.dataformat.MessagePackFactory;
  5. import java.io.IOException;
  6. public class MsgPackMain {
  7. public static void main(String[] args) throws IOException {
  8. Person person = new Person("andrew", "24", "man");
  9. //fastjson
  10. long jsonStartTime = System.currentTimeMillis();
  11. String jsonStr = JSON.toJSONString(person);
  12. System.out.println("json花费时间:" + (System.currentTimeMillis() - jsonStartTime));
  13. System.out.println("json byteArr size is" + jsonStr.getBytes("UTF-8").length);
  14. //msgPack use jackson
  15. ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
  16. long msgPackStartTime = System.currentTimeMillis();
  17. byte[] msgPackByteArr = objectMapper.writeValueAsBytes(person);
  18. System.out.println("msgPack花费时间:" + (System.currentTimeMillis() - msgPackStartTime));
  19. System.out.println("msgPack byteArr size is :" + msgPackByteArr.length);
  20. }
  21. }

测试结果:

  1. json花费时间:199
  2. json byteArr size is40
  3. msgPack花费时间:72
  4. msgPack byteArr size is :28

从测试结果可以看出msgPack明显在速度和size方面都远胜于json,而且由于有jackson的依赖库,所以使用和替换jackson-json都非常简单

二.How to use

下面我们来做一些简单的demo:
引入需要依赖的maven库:

  1. <dependency>
  2. <groupId>org.msgpack</groupId>
  3. <artifactId>jackson-dataformat-msgpack</artifactId>
  4. <version>${msgpack.version}</version>
  5. </dependency>

jackson包装的msgPack,使用非常简单,下面来封装简单的MsgPackUtil

  1. package msgpack;
  2. import com.fasterxml.jackson.core.JsonProcessingException;
  3. import com.fasterxml.jackson.core.type.TypeReference;
  4. import com.fasterxml.jackson.databind.ObjectMapper;
  5. import org.msgpack.jackson.dataformat.MessagePackFactory;
  6. import java.io.IOException;
  7. import java.util.List;
  8. import java.util.Map;
  9. public class MsgPackUtil {
  10. private static final ObjectMapper objectMapper = new ObjectMapper(new MessagePackFactory());
  11. public static <T> T readObj(byte[] byteArr, Class<T> clazz) throws IOException {
  12. return objectMapper.readValue(byteArr, clazz);
  13. }
  14. public static <T> byte[] writeObj(T t) throws JsonProcessingException {
  15. return objectMapper.writeValueAsBytes(t);
  16. }
  17. public static <T> List<T> readList(byte[] listByteArr, TypeReference<List<T>> typeReference) throws IOException {
  18. return objectMapper.readValue(listByteArr, typeReference);
  19. }
  20. public static <T,V> Map<T, V> readMap(byte[] mapByteArr, TypeReference<Map<T, V>> typeReference) throws IOException {
  21. return objectMapper.readValue(mapByteArr, typeReference);
  22. }
  23. }

demo代码:

  1. private static void msgPackJackSonDemo() throws IOException {
  2. //Object
  3. Person person = new Person("andrew", "24", "man");
  4. byte[] personByteArr = MsgPackUtil.writeObj(person);
  5. System.out.println("ObjByteArr size is :" + personByteArr.length);
  6. //使用readValue时候,需要空的构造方法
  7. System.out.println(MsgPackUtil.readObj(personByteArr, Person.class));
  8. //list
  9. List<String> testList = new ArrayList<>(3);
  10. testList.add("hello");
  11. testList.add("msgPack");
  12. testList.add("java");
  13. byte[] listByteArr = MsgPackUtil.writeObj(testList);
  14. System.out.println("listByteArr size is :" + listByteArr.length);
  15. //readList只支持POJO和基本类型List
  16. System.out.println(JSON.toJSONString(MsgPackUtil.readList(listByteArr, new TypeReference<List<String>>() {})));
  17. //map
  18. Map<String, String> testMap = new HashMap<>(3);
  19. testMap.put("hello", "hello");
  20. testMap.put("msgPack", "msgPack");
  21. testMap.put("java", "java");
  22. byte[] mapByteArr = MsgPackUtil.writeObj(testMap);
  23. System.out.println("mapByteArr size is :" + mapByteArr.length);
  24. System.out.println(JSON.toJSONString(MsgPackUtil.readMap(mapByteArr, new TypeReference<Map<String, String>>() {})));
  25. }

三.使用场景

1.适用于将数据存储在类似于mc和redis这类的nosql数据库中,因为数据可以序列化的更小更快,那么在网络上的传输消耗会减少,同时存在redis里面的内存占用也会减少。
2.适用于分布式框架里面多机之间的网络传输,生产上的实现:fluentd https://github.com/fluent/fluentd
3.适用于前后端数据的交互,当前后端完全分离之后,后端可以使用MsgPack代替json以获取更快的速度

四.引用的相关资料:

http://indiegamr.com/cut-your-data-exchange-traffic-by-up-to-50-with-one-line-of-code-msgpack-vs-json/
https://msgpack.org/
https://github.com/msgpack/msgpack-java/blob/develop/msgpack-jackson/README.md

  1. written by 黄文岳
  2. 2018.09.02

发表评论

表情:
评论列表 (有 0 条评论,370人围观)

还没有评论,来说两句吧...

相关阅读

    相关 序列化工Protobuf

    Netty的编码和解码 编写网络应用程序时,因为数据在网络中传输的都是二进制字节码数据,在发送数据时就需要编码,接收数据时就需要解码 codec(编解码器)