`
x-rip
  • 浏览: 105121 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Kryo为什么比Hessian快

 
阅读更多

Kryo 是一个快速高效的Java对象图形序列化框架,它原生支持java,且在java的序列化上甚至优于google著名的序列化框架protobuf。由于protobuf需要编写Schema文件(.proto),且需静态编译。故选择与Kryo类似的序列化框架Hessian作为比较来了解一下Kryo为什么这么快。

序列化的过程中主要有3个指标:

1、对象序列化后的大小

一个对象会被序列化工具序列化为一串byte数组,这其中包含了对象的field值以及元数据信息,使其可以被反序列化回一个对象

2、序列化与反序列化的速度

一个对象被序列化成byte数组的时间取决于它生成/解析byte数组的方法

3、序列化工具本身的速度

序列化工具本身创建会有一定的消耗。

 

从序列化后的大小入手:

测试类:

 

public class Simple implements java.io.Serializable{
  private String name;
  private int age;


  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public int getAge() {
    return age;
  }

  public void setAge(int age) {
    this.age = age;
  }

  static Simple getSimple() {
    Simple simple = new Simple();
    simple.setAge(10);
    simple.setName("XiaoMing");
    return simple;
  }
}

 Kryo序列化:

 

    Kryo kryo = new Kryo();
    kryo.setReferences(false);
    kryo.setRegistrationRequired(false);
    kryo.setInstantiatorStrategy(new StdInstantiatorStrategy());
    output.setOutputStream(new FileOutputStream("file.bin"));
    kryo.writeClassAndObject(output, Simple.getSimple());
    output.flush();

 查看序列化后的结果:



 红色部分:对象头,01 00代表一个未注册过的类

 黑色部分:对象所属的class的名字(kryo中没有设定某个字段的结束符,对于String这种不定长的byte数组,kryo会在其 最后一个byte字节加上x70,如类名最后一位为e,其askii码为x65,在其基础上加x70,即为E5)

 绿色部分:表示这个对象在对象图中的id。即simple对象在对象图中的id为01.

 蓝色部分:表示该类的field。其中02 14中14表示int数值10(映射关系见表1),02和绿色部分的01意思是一样的,即 10这个int对象在对象图中的id为02。以此类推,03表示对象图中的第三个对象,即XiaoMing这个String, 同样其最后一位byte被加了x70。

Hessian序列化:

 

    HessianOutput hout = new HessianOutput(new FileOutputStream("hessian.bin"));
    hout.writeObject(Simple.getSimple());

 查看序列化后的结果:





 
 
 红色部分: 对象头

 黑色部分: 对象所属的类名(类名的askii码)

 紫色部分: 字节类型描述符,表示之后的字节属于何种类型,53表示String,49表示int,等等

 绿色部分: 字节长度描述符,用于表示后面的多少个字节是表示该字节组的

 白色部分: field实际的类型的byte值

 蓝色部分: filed实际的value

 7A: 结束符

 

从序列化后的字节可以看出以下几点:

1、Kryo序列化后比Hessian小很多。(kryo优于hessian)

2、由于Kryo没有将类field的描述信息序列化,所以Kryo需要以自己加载该类的filed。这意味着如果该类没有在kryo中注册,或者该类是第一次被kryo序列化时,kryo需要时间去加载该类(hessian优于kryo)

3、由于2的原因,如果该类已经被kryo加载过,那么kryo保存了其类的信息,就可以很快的将byte数组填入到类的field中,而hessian则需要解析序列化后的byte数组中的field信息,对于序列化过的类,kryo优于hessian。

4、hessian使用了固定长度存储int和long,而kryo则使用的变长,实际中,很大的数据不会经常出现。(kryo优于hessian)

5、hessian将序列化的字段长度写入来确定一段field的结束,而kryo对于String将其最后一位byte+x70用于标识结束(kryo优于hessian)

 

总上所述:

   kryo为了保证序列化的高效性,会加载需要序列化的类,这会带来一定的消耗。可以理解为kryo本身的消耗。由于这点消耗从而可以保证序列化后的大小(避免不必要的源数据)比较小和快速的反序列化。

  通过变长的int和long值保证这种基本数据类型序列化后尽量小

  通过最后一位的特殊操作而非写入长度来标记字段的范围

  本篇未涉及到的地方还有:

使用开源工具reflectasm进行反射而非java本身的反射

        使用objenesis来创建无默认构造函数的类的对象

由于kryo目前只支持Java,所以官方文档也没有给出它序列化所用的kryo grammer,默认支持以下十种。见表一

表一:

 

           # the number of milliseconds since January 1, 1970, 00:00:00 GMT
date       ::= x01 x00 <the number of milliseconds since January 1, 1970, 00:00:00 GMT>

           # boolean true/false
boolean ::= x02 x01	# true
              ::= x02 x00	# false
		   
		   # 8-bit binary data
byte	   ::= x03 <binary-data>	# binary-data  

		   # char
char	   ::= x04 x00 <binary-data>	# binary-data  
	
		   # short
short   ::= x05 [x00-x7F] [x01-xFF]	# 0 to 32767 
	   ::= x05 [x80-xFF] [x01-xFF]	# -23768 to -1
		   
           # 32-bit signed integer( + x02 when increment)
int       ::= x06 x01 [x00-x7E]									# 0 to 63
           ::= x06 x01 [x80-x9E] [x04-xFF]          						# 64 to 4095
           ::= x06 x01 [xA0-xBE] [x00-xFF] [x01-xFF]       				# 4096 to 1048575
           ::= x06 x01 [xC0-xDE] [x00-xFF] [x00-xFF] [x01-xFF]      		# 1048576 to 268435455
	   ::= x06 x01 [xE0-xFE] [x00-xFF] [x00-xFF] [x00-xFF] [x01-x07]  	# 268435456 to 2147483647
           ::= x06 x01 [x01-x7F]									# -1 to -64
           ::= x06 x01 [x81-x9F] [x04-xFF]          						# -65 to -4096
           ::= x06 x01 [xA1-xBF] [x00-xFF] [x01-xFF]       				# -4097 to -1048576
           ::= x06 x01 [xC1-xDF] [x00-xFF] [x00-xFF] [x01-xFF]      		# -1048577 to -268435456
           ::= x06 x01 [xE1-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x01-x07]  	# -268435457 to -2147483648
		   
		   # 64-bit signed long integer ( +x02 when incerment)
long       ::= x07 x01 [x00-x7E]																						# 0 to 63
           ::= x07 x01 [x80-x8E] [x08-xFF]          																	# 64 to 2047
           ::= x07 x01 [x90-x9E] [x00-xFF] [x01-xFF]       																# 2048 to 524287
           ::= x07 x01 [xA0-xAE] [x00-xFF] [x00-xFF] [x01-xFF]      													# 524288 to 134217727
           ::= x07 x01 [xB0-xBE] [x00-xFF] [x00-xFF] [x00-xFF] [x01-xFF]      											# 134217728 to 34359738367
	   ::= x07 x01 [xC0-xCE] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x01-xFF]      								# 34359738368 to 8796093022207
           ::= x07 x01 [xD0-xDE] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x01-xFF]      						# 8796093022208 to 2251799813685247
	   ::= x07 x01 [xE0-xEE] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x01-xFF]      			# 2251799813685248 to 576460752303423487
	   ::= x07 x01 [xF0-xFE] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x01-x0F]      	# 576460752303423488 to 9223372036854775807
	   ::= x07 x01 [x01-x7F]																						# -1 to -64
           ::= x07 x01 [x81-x8F] [x08-xFF]          																	# -65 to -2048
           ::= x07 x01 [x91-x9F] [x00-xFF] [x01-xFF]       																# -2049 to -524288
           ::= x07 x01 [xA1-xAF] [x00-xFF] [x00-xFF] [x01-xFF]      													# -524289 to -134217728
           ::= x07 x01 [xB1-xBF] [x00-xFF] [x00-xFF] [x00-xFF] [x01-xFF]      											# -134217729 to -34359738368
	   ::= x07 x01 [xC1-xCF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x01-xFF]      								# -34359738369 to -8796093022208
	   ::= x07 x01 [xD1-xDF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x01-xFF]      						# -8796093022209 to -2251799813685248
	   ::= x07 x01 [xE1-xEF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x01-xFF]      			# -2251799813685249 to -576460752303423488
	   ::= x07 x01 [xF1-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x00-xFF] [x01-x0F]      	# -576460752303423489 to -9223372036854775808
  
		   # float/Float
float      ::= x08 x01 <floatToInt>

		   # double/Double
double     ::= x09 x01 <doubleToLong>

		   # String
String     ::= x0A x01 x82 <utf8-data>																	# data.length()=1
		   ::= x0A x01 <utf8-data.subString(0,data.length()-2)> <utf8-data.charAt(data.length-1)>+x70	# data.length()>1

	        # The class not registered in kryo
Object	::= x01 x00 <(string)className> <(byte)id> <(Object)objectFieldValue ordered by fieldName> 

 

 

  • 大小: 16.6 KB
  • 大小: 22.8 KB
分享到:
评论
3 楼 xurping 2018-05-23  
kolor 写道
呵呵 ,一直在用kryo,不过都没有去分析过它生成的字节码,学习了
不过,kryo有个缺陷,它生成的字节码中是不包含field元数据的,这样的话,在兼容性上就很难处理了,比如你文中提到的类Simple,它有两个字段,假如后来又给它增加了个字段,这样新旧实体就没法兼容了


可以通过自定义序列化器实现兼容
2 楼 xjl456852 2016-07-19  
你好,我感觉那个加x70是不是有问题啊.

x65在其基础上加x70 得到的结果不是xD5吗? 怎么会是xE5呢
1 楼 kolor 2012-09-07  
呵呵 ,一直在用kryo,不过都没有去分析过它生成的字节码,学习了
不过,kryo有个缺陷,它生成的字节码中是不包含field元数据的,这样的话,在兼容性上就很难处理了,比如你文中提到的类Simple,它有两个字段,假如后来又给它增加了个字段,这样新旧实体就没法兼容了

相关推荐

    java版分销系统源码-NettyRPC:NettyRPC是基于Netty的高性能javarpc服务器,使用kryo,hessian,prot

    消息网络传输除了JDK原生的对象序列化方式,还支持目前主流的编码解码器:kryo、hessian。 Netty网络模型采用主从Reactor线程模型,提升RPC服务器并行吞吐性能。 多线程模型采用guava线程库进行封装。 NettyRPC 1.0 ...

    mango:高性能,开源Java RPC框架

    支持各种序列化协议,例如 ,Kryo,Hessian,msgpack,Jackson,Fastjson。 支持高级功能,例如负载平衡(随机,循环),高可用性策略(故障转移,故障转移)。 支持诸如ZooKeeper或Consul之类的服务发现服务。 ...

    My-RPC-Framework:一个简单的RPC框架的实现

    实现了四种序列化算法,Json 方式、Kryo 算法、Hessian 算法与 Google Protobuf 方式(默认采用 Kryo方式序列化) 实现了两种负载均衡算法:随机算法与轮转算法 使用 Nacos 作为注册中心,管理服务提供者信息 消费端...

    RxCache:适用于Java和Android的本地React式缓存。 现在,它支持堆内存,堆外内存和磁盘缓存

    Persistence 额外支持使用 FastJSON、Moshi、Kryo、Hessian、FST、Protobuf 实现对象的序列化和反序列化 Persistence 的 AbstractConverter 拥有加密功能,默认使用 AES 128、DES 算法进行加密 支持显示

    大数据技术体系图谱.pptx

    数据传输 序列化 JSON 01 Protobuf 02 Hessian 03 FST 04 MessagePack 05 Avro 06 大数据技术体系图谱全文共96页,当前为第12页。 序列化 数据传输 Kryo 大数据技术体系图谱全文共96页,当前为第13页。 03 数据存储...

    2阶段提交分布式事务中间件,一致性分布式事务框架

    一致性分布式事务框架。支持所有弹簧版本,无缝集成。提供对 springcloud dubbo motan RPC 框架的支持。...事务日志序列化支持:java hessian kryo protostuff。SPI扩展:用户可以自定义序列化和事务日志的存储

    agileway:提供Java,Web,各种类库增强,应避免996。目前已支持feign,redis,datasource,shiro,httpclient,rest,codec,serialize等

    支持基于hessian序列化框架实现 支持基于Jdk Serializable规范实现 支持基于easyjson,jackson实现 支持基于Kryo序列化框架实现 支持基于MsgPack序列化规范的实现 支持基于Protostuff序列化框架实现 支持基于XSON...

    lostrpc:异步 rpc frm

    支持很多编码解码器(Protobuf【跨语言】、Hessian、JDK、Kryo) 支持自定义Codec 支持自定义Protocol 实现了消息的同步分发、异步分发 支持自定义消息分发 服务端支持消息同步处理、全局异步处理、链接消息有序异步...

    亲缘关系

    rsocket等协议kinrpc协议支持KRYO,HESSIAN,JAVA,JSON等序列化方案kinrpc协议下支持provider服务接口方法初始化返回结果通过org.kin.kinrpc.rpc.RpcServiceContext设置未来参数返回值是未来进一步工作代码优化, ...

    myth分布式开发框架-其他

    事务日志序列化支持:Java Hessian Kryo Protostuff Spi扩展:用户可以自定义序列化和事务日志的存储 先决条件: 您必须使用jdk1.8 + 您必须是spring框架的用户 您必须使用消息传递中间件 您必须使用dubbo,motan和...

    java8源码-tcc:TCC分布式事务框架

    java8 源码 TCC分布式事务框架 ...:hessian,kryo。 内置经典的分布式事务场景demo工程,并有swagger-ui可视化界面。 内置本地事务状态机,实现confirm和cancel操作不会被多次执行,放宽了幂等性要求。

    dubbo、dubbox编译所需jar包

    hessian-lite-3.2.1-fixed-2.jar hibernate-validator-4.2.0.Final.jar hsqldb-1.7.1.jar htmlunit-1.9.jar httpclient-4.0.1.jar httpclient-4.1.2.jar httpclient-4.2.5.jar httpclient-4.4.jar ...

    木星:木星是一种性能非常不错的,轻量级的分布式服务框架

    木星: Jupiter是一种性能非常不错的,轻量级的分布式服务框架 木星建筑: ═ ═ ═▷ init ─ ─ ─ ▷ async ──────:play_button: sync ---------------------------------------------------------------...

Global site tag (gtag.js) - Google Analytics