一个高性能、小而美的序列化工具!

简介: Kryo是一个高性能的序列化/反序列化工具,由于其变长存储特性并使用了字节码生成机制,拥有较高的运行速度和较小的体积,在某些场景中成为了除Json、Protobuf之外的选择。

image.png

记录类型信息

这算是kryo的一个特点,可以把对象信息直接写到序列化数据里,反序列化的时候可以精确地找到原始类信息,不会出错,这意味着在写readxxx方法时,无需传入Class或Type类信息。


相应的,kryo提供两种读写方式。记录类型信息的writeClassAndObject/readClassAndObject方法,以及传统的writeObject/readObject方法。


线程安全

kryo的对象本身不是线程安全的,所以我们有两种选择来保障线程安全。


使用Threadlocal来保障线程安全:

image.png

实例化器

在上面注意到kryo.setInstantiatorStrategy(new Kryo.DefaultInstantiatorStrategy(new StdInstantiatorStrategy())); 这句话显示指定了实例化器。


在一些依赖了kryo的开源软件中,可能由于实例化器指定的问题而抛出空指针异常。例如hive的某些版本中,默认指定了StdInstantiatorStrategy。

public static ThreadLocal<Kryo> runtimeSerializationKryo = new ThreadLocal<Kryo>() {
    @Override
    protected synchronized Kryo initialValue() {
        Kryo kryo = new Kryo();
        kryo.setClassLoader(Thread.currentThread().getContextClassLoader());
        kryo.register(java.sql.Date.class, new SqlDateSerializer());
        kryo.register(java.sql.Timestamp.class, new TimestampSerializer());
        kryo.register(Path.class, new PathSerializer());
        kryo.setInstantiatorStrategy(new StdInstantiatorStrategy());
        ......
            return kryo;
    };
};

而StdInstantiatorStrategy在是依据JVM version信息及JVM vendor信息创建对象的,可以不调用对象的任何构造方法创建对象。

那么例如碰到ArrayList这样的对象时候,就会出问题。观察一下ArrayList的源码:

public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

既然没有调用构造器,那么这里elementData会是NULL,那么在调用类似ensureCapacity方法时,就会抛出一个异常。

 public void ensureCapacity(int minCapacity) {
     if (minCapacity > elementData.length
         && !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
              && minCapacity <= DEFAULT_CAPACITY)) {
         modCount++;
         grow(minCapacity);
     }
 }

解决方案很简单,就如框架中代码写的一样,显示指定实例化器,首先使用默认无参构造策略DefaultInstantiatorStrategy,若创建对象失败再采用StdInstantiatorStrategy。


类注册

当kryo写一个对象的实例的时候,默认需要将类的完全限定名称写入。将类名一同写入序列化数据中是比较低效的,所以kryo支持通过类注册进行优化。

image.png

注册会给每一个class一个int类型的Id相关联,这显然比类名称高效,但同时要求反序列化的时候的Id必须与序列化过程中一致。这意味着注册的顺序非常重要。


但是由于现实原因,同样的代码,同样的Class在不同的机器上注册编号任然不能保证一致,所以多机器部署时候反序列化可能会出现问题。


所以kryo默认会禁止类注册,当然如果想要打开这个属性,可以通过kryo.setRegistrationRequired(true);打开。


循环引用

这是对循环引用的支持,可以有效防止栈内存溢出,kryo默认会打开这个属性。当你确定不会有循环引用发生的时候,可以通过kryo.setReferences(false);关闭循环引用检测,从而提高一些性能。


可变长存储

kryo对int和long类型都采用了可变长存储的机制,以int为例,一般需要4个字节去存储,而对kryo来说,可以通过1-5个变长字节去存储,从而避免高位都是0的浪费。


最多需要5个字节存储是因为,在变长存储int过程中,一个字节的8位用来存储有效数字的只有7位,最高位用于标记是否还需读取下一个字节,1表示需要,0表示不需要。


在对string的存储中也有变长存储的应用,string序列化的整体结构为length+内容,那么length也会使用变长int写入字符的长度。


配合缓存使用的场景

在实际开发中,class增删字段是很常见的事情,但对于kryo来说,确是不支持的,而如果恰好需要使用缓存,那么这个问题会被放得更大。


例如一个对象使用kryo序列化后,数据放入了缓存中,而这时候如果这个对象增删了一个属性,那么缓存中反序列化的时候就会报错。所以频繁使用缓存的场景,可以尽量避免kryo。


不过现在的Kryo提供了兼容性的支持,使用CompatibleFieldSerializer.class,在kryo.writeClassAndObject时候写入的信息如下:


class name|field length|field1 name|field2 name|field1 value| filed2 value

而在读入kryo.readClassAndObject时,会先读入field names,然后匹配当前反序列化类的field和顺序再构造结果。


当然如果在做好缓存隔离的情况下,这一切都不用在意。

目录
相关文章
|
缓存 自然语言处理 分布式计算
Fury:一个基于JIT动态编译的高性能多语言原生序列化框架
Fury是一个基于JIT动态编译的多语言原生序列化框架,支持Java/Python/Golang/C++等语言,提供全自动的对象多语言/跨语言序列化能力,以及相比于别的框架最高20~200倍的性能。
Fury:一个基于JIT动态编译的高性能多语言原生序列化框架
|
9月前
|
Java Maven
ProtostuffUtil—快速序列化和反序列化对象工具
ProtostuffUtil—快速序列化和反序列化对象工具
|
7月前
|
消息中间件 Dubbo Java
Simple RPC - 02 通用高性能序列化和反序列化设计与实现
Simple RPC - 02 通用高性能序列化和反序列化设计与实现
46 2
|
9月前
|
XML 存储 JSON
数据序列化工具 Protobuf 编码&避坑指南
我们现在所有的协议、配置、数据库的表达都是以 protobuf 来进行承载的,所以我想深入总结一下 protobuf 这个协议,以免踩坑。 先简单介绍一下 Protocol Buffers(protobuf),它是 Google 开发的一种数据序列化协议(与 XML、JSON 类似)。它具有很多优点,但也有一些需要注意的缺点: 优点: 效率高:Protobuf 以二进制格式存储数据,比如 XML 和 JSON 等文本格式更紧凑,也更快。序列化和反序列化的速度也很快。 跨语言支持:Protobuf 支持多种编程语言,包括 C++、Java、Python 等。 清晰的结构定义:使用 prot
|
9月前
|
Java 程序员
JavaIO编程(键盘输入,缓冲输入流、Scanner工具、序列化与反序列化)附带相关面试题
1.System类对io的支持,2.BufferReader缓冲输入流,3.Scanner输入流工具,4.对象序列化
55 0
|
10月前
|
缓存 自然语言处理 Rust
比JDK最高快170倍,蚂蚁集团开源高性能多语言序列化框架Fury
Fury是一个基于JIT动态编译和零拷贝的多语言序列化框架,支持Java/Python/Golang/JavaScript/C++等语言,提供全自动的对象多语言/跨语言序列化能力,和相比JDK最高170倍的性能。经过多年蚂蚁核心场景的锤炼打磨,现已正式在Github对外开源:https://github.com/alipay/fury
2387 5
|
12月前
|
JSON 数据格式 Python
django drf 案例--实现url编码和json和dict格式转化小工具(涉及定义模型类,序列化器,类视图,路由),接口测试
django drf 案例--实现url编码和json和dict格式转化小工具(涉及定义模型类,序列化器,类视图,路由),接口测试
|
消息中间件 NoSQL 安全
【Spring技术原理】采用protostuff和kryo高性能序列化框架实现RestTemplate的序列化组件
【Spring技术原理】采用protostuff和kryo高性能序列化框架实现RestTemplate的序列化组件
234 0
【Spring技术原理】采用protostuff和kryo高性能序列化框架实现RestTemplate的序列化组件
|
存储 安全 NoSQL
Java高性能序列化工具Kryo序列化
Java高性能序列化工具Kryo序列化
223 0
Java高性能序列化工具Kryo序列化
|
存储 缓存 自然语言处理
Fury:一个基于JIT的高性能多语言原生序列化框架
Fury是一个基于JIT的多语言原生序列化框架,支持Java/Python/Golang/C++等语言,提供全自动的对象多语言/跨语言序列化能力,和相比别的框架最高30~200倍的性能。背景过去十多年大数据和分布式系统蓬勃发展,序列化是其频繁使用的技术。当对象需要跨进程、跨语言、跨节点传输、持久化、状态读写时,都需要进行序列化,其性能和易用性影响着系统的运行效率和开发效率。对于Java序列化,尽管
1078 0
Fury:一个基于JIT的高性能多语言原生序列化框架