使用Kryo的序列化方式提升Netty性能
2014-06-03 00:00
357 查看
摘要: 使用默认的Java序列化方式,性能比较差。目前高性能的序列化主要是Protobuf和Kryo。本文介绍使用Kryo+Netty的方式提升Netty传输性能。
为什么选择Kryo?
首先,Kryo的序列化方式,在性能方面是比较好的,和Protobuf差不多,比Java原生的序列化方式快多了。由于本篇文章主要想说明Kryo和Netty的整合,所以关于Kryo序列化的原理请查阅其他文章。
其次,Protobuf是个跨语言的解决方案,需要预先定义schema,然后通过预编译生成代码。如果是Java单语言调用,Kryo是更好的选择,不需要预编译,不需要schema。
使用连接池
Kryo对象非线程安全,但是频繁new会造成巨大的性能损耗,所以应该使用连接池。推荐使用apache的commons-pool2。
使用Kryo序列化对象要注意的地方
正常情况下,需要被序列化的对象有默认的无参构造器。
不需要实现Serializable接口。
如果想使用不带无参构造器的对象也能正确反序列化,可以考虑kryo-serializers包,使用其提供的KryoReflectionFactorySupport,会采用jdk的ReflectionFactory反射的生成对象。该方式不需要提供默认的构造器也可以成功反序列化,但是由于不调用构造器,如果在构造器中维护了别的类的状态, 会导致别的类状态失效。所以最佳实践是,构造器最好只用于初始化本类的属性。注意:如果使用KryoReflectionFactorySupport而导致错误,有可能不抛异常,而是状态直接错误,很难调试,建议谨慎使用。
如果调用了List的sublist方法生成的SubList对象,或者使用Arrays.asList方法生成的对象,都不能正确的序列化。仍然可以使用kryo-serializers包所提供的SubListSerializers,ArraysAsListSerializer等完成正确序列化。
对于自定义的特殊类,可以自定义实现FieldSerialier的create方法,并注册到Kryo的实例化对象中去。
使用Kryo作为Netty序列化对象的协议
通过实现MessageToByteEncoder接口,实现encode对象
通过实现LengthFieldBasedFrameDecoder接口,实现decode对象
做了一下测试,发送1万次请求,java内置序列化耗时6.776秒,Kryo耗时3.160秒;发送10万次请求,java内置序列化耗时48.555秒,Kryo耗时15.423秒。当然这个数据因环境而异,但是提升效果非常显著。
具体代码可参见:
Kryo序列化部分:https://github.com/terrymanu/miracle-framework/tree/master/miracle-framework-common/miracle-framework-common-serialize
Kryo和Netty整合部分:https://github.com/terrymanu/miracle-framework/tree/master/miracle-framework-remote/miracle-framework-remote-netty
为什么选择Kryo?
首先,Kryo的序列化方式,在性能方面是比较好的,和Protobuf差不多,比Java原生的序列化方式快多了。由于本篇文章主要想说明Kryo和Netty的整合,所以关于Kryo序列化的原理请查阅其他文章。
其次,Protobuf是个跨语言的解决方案,需要预先定义schema,然后通过预编译生成代码。如果是Java单语言调用,Kryo是更好的选择,不需要预编译,不需要schema。
使用连接池
Kryo对象非线程安全,但是频繁new会造成巨大的性能损耗,所以应该使用连接池。推荐使用apache的commons-pool2。
使用Kryo序列化对象要注意的地方
正常情况下,需要被序列化的对象有默认的无参构造器。
不需要实现Serializable接口。
如果想使用不带无参构造器的对象也能正确反序列化,可以考虑kryo-serializers包,使用其提供的KryoReflectionFactorySupport,会采用jdk的ReflectionFactory反射的生成对象。该方式不需要提供默认的构造器也可以成功反序列化,但是由于不调用构造器,如果在构造器中维护了别的类的状态, 会导致别的类状态失效。所以最佳实践是,构造器最好只用于初始化本类的属性。注意:如果使用KryoReflectionFactorySupport而导致错误,有可能不抛异常,而是状态直接错误,很难调试,建议谨慎使用。
如果调用了List的sublist方法生成的SubList对象,或者使用Arrays.asList方法生成的对象,都不能正确的序列化。仍然可以使用kryo-serializers包所提供的SubListSerializers,ArraysAsListSerializer等完成正确序列化。
对于自定义的特殊类,可以自定义实现FieldSerialier的create方法,并注册到Kryo的实例化对象中去。
使用Kryo作为Netty序列化对象的协议
通过实现MessageToByteEncoder接口,实现encode对象
通过实现LengthFieldBasedFrameDecoder接口,实现decode对象
做了一下测试,发送1万次请求,java内置序列化耗时6.776秒,Kryo耗时3.160秒;发送10万次请求,java内置序列化耗时48.555秒,Kryo耗时15.423秒。当然这个数据因环境而异,但是提升效果非常显著。
具体代码可参见:
Kryo序列化部分:https://github.com/terrymanu/miracle-framework/tree/master/miracle-framework-common/miracle-framework-common-serialize
Kryo和Netty整合部分:https://github.com/terrymanu/miracle-framework/tree/master/miracle-framework-remote/miracle-framework-remote-netty
相关文章推荐
- 使用ASP.NET AJAX异步调用Web Service和页面中的类方法(10):服务器端和客户端数据类型的自动转换:以XML方式序列化数据、小结
- Android中使用PULL方式解析XML和XmlSerializer进行序列化
- Dubbo中使用高效的Java序列化(Kryo和FST)
- 使用Intent传递对象的两种方式(序列化)
- Netty之传输POJO(使用JBoss的Marshalling序列化方式)
- 使用序列化的方式来读取XML配置文件
- Redis缓存中使用Kryo序列化工具并且修改内容同时更新缓存
- GSON使用笔记(1) -- 序列化时排除字段的几种方式
- 序列化框架的使用及性能对比Kryo、Hessian、Protostuff、java原生
- spring-data-redis 整合,以及使用kryo序列化代替jdk原生序列化机制
- 使用文件方式实现Java序列化
- 基于kryonet的RPC,使用kryo进行序列化
- unserialize的这个问题是由一个emlog论坛用户在使用时报错而发现的 问题表现情况如下: emlog缓存的保存方式是将php的数据对象(数组)序列化(serialize)后以文件的形式存放,
- spark性能调优之使用Kryo序列化
- GSON使用笔记(1) -- 序列化时排除字段的几种方式
- 序列化对象,使用的三种方式:Xml,Binary,Soap
- nginx连接后端服务时,使用upstream的方式,并且设置keepalive可以建立长连接,减少创建连接的消耗,提升效率
- Java 序列化--- Kryo使用简单例子
- 传统Socket编程传递POJO(使用Java自带的序列化方式)
- 在Dubbo中使用高效的Java序列化(Kryo和FST)