关于对象序列化

时间:2020-06-17 23:58:36   收藏:0   阅读:111

前言

序列化是指将对象转换成可传输或可存储的形式的过程。常见的如文件存储,网络传输。

序列化是个过程,按照什么方式序列化呢?不同的序列化方式得到的结果也不近相同。微服务里超高的调用频率要求编解码的速度更快,大数据里要求数据存储的报文体积更小。

1. 序列化的定义 应用场景

如上面说到序列化用于将对象转换成可传输或存储的形式的过程。反序列化使用存储或传输内容重新创建对象的过程。

JSON/XML 序列化和 二进制序列化

网络传输中我们会序列化成JSON或XML,可读性好,通用。但直观和通用的同时也带来了性能差的缺点。信息冗余了很多,键值对方面,会有重复的key值。

而序列化成二进制流,然后在二进制流中规定相关协议。我们就可按照协议来恢复成目标对象。

2. 关于二进制序列化

2.1 优化原理

空间优化:

时间优化:

2.2 序列化评判指标

以上有些指标之间是相互冲突的,实现的时候必须要在他们之间做出平衡。比如体积和表达力之间很显然是矛盾的。另外往往支持多语言的话,那么他在某一个语言上的自由度就要打折扣。比如Protobuf支持跨语言,就得使用IDL。但是他的纯java版本protostuff是完全不需要IDL的,使用起来特别灵活。

2.3 常见框架

3. 实现原理

  1. 使用 TLV 进行编码

TLV本身是一个电信领域的编码标准。TLV指的是由数据的类型Tag,数据的长度Length,数据的值Value组成的三元组结构体,几乎可以描任意数据类型,TLV还可以继续嵌套,Value也可以是一个TLV结构,基于这种嵌套的特性,可以让我们用来表达复杂对象。

Protobuf 就使用了 TLV 的结构,结构如下图
技术分享图片
2. varint 算法

varint算法是一种变长的数值编码算法(variable integer)。我们都知道,在语言规范中,int总是固定为4个字节长度。取值范围为-231——231-1,即-2147483648——2147483647。但根据统计发现,程序中使用到的大部分int都不需要这么长。varint算法正是利用到了这一点来做优化。

数值非常小时,只需要使用一个字节来存储,数值稍微大一点可以使用 2 个字节,再大一点就是 3 个字节,它还可以超过 4 个字节用来表达长整形数字。

其原理也很简单,就是保留每个字节的最高位的 bit 来标识是否后面还有字节,1 表示还有字节需要继续读,0 表示到读到当前字节就结束。

技术分享图片

  1. 局部再调优

对于某些局部细节还可以继续做优化。

对于负数,可以通过ZigZag 编码映射到正数处理。

zigzag 编码将整数范围一一映射到自然数范围,然后再进行 varint 编码。

0 => 0
-1 => 1
1 => 2
-2 => 3
2 => 4
-3 => 5
3 => 6

zigzag 将负数编码成正奇数,正数编码成偶数。解码的时候遇到偶数直接除 2 就是原值,遇到奇数就加 1 除 2 再取负就是原值。

4. 序列化的坑

References

原文:https://www.cnblogs.com/wei57960/p/13155094.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!