文档章节

Kryo 序列化历程

y
 yangming0322
发布于 2016/08/30 15:42
字数 1631
阅读 650
收藏 2

使用的版本是 Kryo-4.0.0

背景: 使用redis 进行存储对象,随着业务不断的攀升,redis 的空间占用率增长迅猛.读取数据时引发了网卡流量超过1m等问题. 因此引入序列话+压缩比高的技术,对要存储的对象进行压缩后存储.

相关资料:

https://github.com/EsotericSoftware/kryo
各种序列化方式的性能、空间比较
https://github.com/eishay/jvm-serializers/wiki

1,选择序列化方式

FieldSerializer 速度快,压缩比高,缺点是不能向前,向后兼容
VersionFieldSerializer : 可以向后兼容,但不能向前兼容,也就是类可以扩展一个字段 ,扩展后仍然能读取线上的缓存,但是新序列化的数据用旧的对象读取 会报错
CompatibleFieldSerializer :可以向前,向后兼容,但是会稍慢

最后结合项目中要存储对象 变更频率非常低的特性,决定使用 FieldSerializer

 

2,实现了第一个版本后测试 测试发现类没有构造函数导致反序列化失败

因此增加了通用的对无默认构造函数的扩展支持kryox

http://my.oschina.net/yangming0322/blog/739882

引入kryox

 private ThreadLocal<Kryo> holder = new ThreadLocal<Kryo>() {
    @Override
    protected Kryo initialValue() {
      return newKryo();
    }
  };

  /**
   * 返回新的kryo
   * 
   * @return
   */
  private Kryo newKryo() {
    Kryox kryo = new Kryox();
    // set property
    kryo.setDefaultSerializer(serializerClass);
    UnmodifiableCollectionsSerializer.registerSerializers( kryo );
    SynchronizedCollectionsSerializer.registerSerializers( kryo );
    return kryo;
  }

引入kryox 后发现新的问题 序列化的性能降低,经过一顿分析折腾后 ,遭到原因,就是无默认构造函数的类,反序列化,虽然通过kryx 已经能支持. 但是效率和有构造函数对比4:1 左右,代价不容小觑,尤其是针对访问量特别大的类来说.直接导致了系统性能的大幅下降.

 

3,去掉kryox ,给无构造函数的类增加包装类, 所有引用的地方 存储和读取时进行转换修改.

ok ,性能和压缩比都提升上来了.

效果:

总结:  kryo 在此业务中的压缩比在 70% ,单个用户对象整合引用关系后可以减少1k左右

4,现在进入了第四阶段,批量压力测试.

 a.不断的发现,没有构造函数的类报错,逐一增加包装类.

 b.实体类中使用了UUID 类型(无默认构造函数),//解决方案就是替换成String 当然类比较少所以算是简单应付.,因为修改了类的定义,所以上线的一刻会有老数据反序列化异常的风险,经过评估,增加了一个控制.如果遇到反序列化异常,就重新读取db加载覆盖到缓存中.

 c.部分类 序列化后不能反序列化  类中有特殊的属性 如: 

此类在反序列化时 提示:

com.esotericsoftware.kryo.KryoException: Unable to find class: OLE_USER
Serialization trace:
authorities (com.chanjet.csp.boss.cia.security.wrap.OAuth2AuthenticationWrap)
    at com.esotericsoftware.kryo.util.DefaultClassResolver.readName(DefaultClassResolver.java:160)
    at com.esotericsoftware.kryo.util.DefaultClassResolver.readClass(DefaultClassResolver.java:133)
    at com.esotericsoftware.kryo.Kryo.readClass(Kryo.java:693)
    at com.esotericsoftware.kryo.Kryo.readClassAndObject(Kryo.java:804)
    at com.esotericsoftware.kryo.serializers.CollectionSerializer.read(CollectionSerializer.java:134)
    at com.esotericsoftware.kryo.serializers.CollectionSerializer.read(CollectionSerializer.java:40)
    at com.esotericsoftware.kryo.Kryo.readObject(Kryo.java:731)
    at com.esotericsoftware.kryo.serializers.ObjectField.read(ObjectField.java:125)
    at com.esotericsoftware.kryo.serializers.FieldSerializer.read(FieldSerializer.java:540)
    at com.esotericsoftware.kryo.Kryo.readClassAndObject(Kryo.java:813)
    at com.chanjet.infrastructure.cache.impl.KryoJedisCacheServiceImpl.deserializeValue(KryoJedisCacheServiceImpl.java:159)
    at com.chanjet.infrastructure.cache.impl.KryoJedisCacheServiceImpl.get(KryoJedisCacheServiceImpl.java:226)
    at com.chanjet.infrastructure.cache.impl.JedisCacheServiceImplProxy.get(JedisCacheServiceImplProxy.java:62)
    at com.chanjet.csp.boss.cia.security.authentication.CiaAuthenticationManager.getOAuthentication(CiaAuthenticationManager.java:56)
    at com.chanjet.csp.boss.cia.security.authentication.CiaAuthenticationManager.getReleatedOAuth2AuthenticationByKey(CiaAuthenticationManager.java:50)
    at com.chanjet.csp.boss.cia.security.oauth2.token.CacheTokenStore.readAuthentication(CacheTokenStore.java:76)
    at com.chanjet.csp.boss.cia.security.oauth2.token.CacheTokenStore.getAccessToken(CacheTokenStore.java:61)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:198)
    at com.sun.proxy.$Proxy76.getAccessToken(Unknown Source)
    at com.chanjet.csp.boss.cia.security.oauth2.token.DefaultTokenServices._createAccessToken(DefaultTokenServices.java:124)
    at com.chanjet.csp.boss.cia.security.oauth2.token.DefaultTokenServices.createAccessToken(DefaultTokenServices.java:116)
    at org.springframework.security.oauth2.provider.token.AbstractTokenGranter.getAccessToken(AbstractTokenGranter.java:68)
    at org.springframework.security.oauth2.provider.token.AbstractTokenGranter.grant(AbstractTokenGranter.java:60)
    at com.chanjet.csp.boss.cia.api.AuthenticationApi.clientAuthenticationWithUserInfo(AuthenticationApi.java:1219)
    at com.chanjet.csp.boss.cia.api.AuthenticationApi$$FastClassByCGLIB$$8943a6dc.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:698)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:80)
    at com.chanjet.csp.boss.cia.aop.log.MqHandlerAspect.aroundAdvice(MqHandlerAspect.java:42)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:621)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:610)
    at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:65)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:80)
    at com.chanjet.csp.boss.cia.aop.log.ApiLogHandlerAspect.aroundAdvice(ApiLogHandlerAspect.java:119)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:621)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:610)
    at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:65)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:91)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
    at com.chanjet.csp.boss.cia.api.AuthenticationApi$$EnhancerByCGLIB$$b471f4e.clientAuthenticationWithUserInfo(<generated>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:219)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:768)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:703)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:838)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:502)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1148)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1148)
    at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:387)
    at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
    at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
    at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
    at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:417)
    at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230)
    at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at org.mortbay.jetty.Server.handle(Server.java:326)
    at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:534)
    at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:879)
    at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:747)
    at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
    at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
    at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:520)
Caused by: java.lang.ClassNotFoundException: OLE_USER
    at org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy.loadClass(SelfFirstStrategy.java:50)
    at org.codehaus.plexus.classworlds.realm.ClassRealm.unsynchronizedLoadClass(ClassRealm.java:259)
    at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:235)
    at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:227)
    at org.mortbay.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:401)
    at org.mortbay.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:363)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)
    at com.esotericsoftware.kryo.util.DefaultClassResolver.readName(DefaultClassResolver.java:154)
    ... 115 more

 

(插曲:  在解决序列化方案的问题,我们同时分析了一下,现有的redis 使用模式.发现有些对象重复的写入到redis.这样体积偏大. 

于是穿插增加对 业务代码的修改,对象只写入一次,其他地方存 引用关系.

使用的时候两次查找.)

这个问题终于解决了 ,问题的表象是反序列化失败, 实际是序列化和反序列化时用的kryo版本不一致导致.

具体为a工程序列化的结果 b工程反序列化失败,但是a自己可以反序列化(呃.算是废话吧.)

分析发现编译后有kryo3个版本

kryo2.24.0,kryo-3.0.3,kryo-4.0.0

工程依赖了dubbo dubbo默认依赖了kryo2.24.0

工程依赖了kryo-serializers-0.38 ,kryo-serializers 依赖了 kryo-3.0.3

最终解决方案:

工程依赖了kryo-serializers,他又依赖了kryo-3.0.3 ,我的工程要依赖4.0.0 于是出现三个依赖. 导致出现诡异的现象,所以最终的解决方案是在pom中声明去掉 dubbo 和 kryo-serializers,只保留4.0.0

备注: 因为工程中统一使用kryo4.0.0, 已经去掉了dubbo 的kryo依赖, 此时要注意所有dubbo工程中最好使用其他的序列化包,避免出现kryo 因此的工程间序列化问题(kryo 各版本间是有兼容风险的)

待续,不断的踩雷中  如果有大侠遇到过此类问题,请指路 多谢 ..... 

 

© 著作权归作者所有

上一篇: Kryox
下一篇: maven 依赖树查看
y
粉丝 0
博文 17
码字总数 6387
作品 0
西城
高级程序员
私信 提问
加载中

评论(1)

天山只影
天山只影
博主你好,我也遇到了这种没有无参构造器,无法反序列化的问题。请问你的包装类是怎么写的?
Kryo 为什么比 Hessian 快

Kryo 是一个快速高效的Java对象图形序列化框架,它原生支持java,且在java的序列化上甚至优于google著名的序列化框架protobuf。由于 protobuf需要编写Schema文件(.proto),且需静态编译。故...

jmppok
2015/03/25
0
0
Kryo 为什么比 Hessian 快

Kryo 是一个快速高效的Java对象图形序列化框架,它原生支持java,且在java的序列化上甚至优于google著名的序列化框架protobuf。由于 protobuf需要编写Schema文件(.proto),且需静态编译。故...

鉴客
2013/03/04
11K
5
spark-kryo序列化(spark优化点)

广播大变量,每个executor可以对应一个blockmanager里面存着变量,虽然我们减少了网络传输,减少了内存占用整体空间,但是还可以进一步减小网络传输和内存占用空间,所以我们可以用kryo序列化...

SET
2016/10/29
575
0
spark性能优化之使用高性能序列化类库

如果使用序列化技术,在执行序列化操作的时候很慢或者是序列化之后的数据量还是很大,那么会让分布式应用程序性能下降很多,spark自身就会在一些地方对数据进行序列化,比如shuffle写磁盘,还...

恶魔苏醒ing
2017/05/10
0
0
JAVA序列化 框架 Kryo

Kryo是一个快速高效的Java序列化框架,旨在提供快速、高效和易用的API。无论文件、数据库或网络数据Kryo都可以随时完成序列化。Kryo还可以执行自动深拷贝(克隆)、浅拷贝(克隆)。这是对象...

ovirtKg
2016/11/08
144
0

没有更多内容

加载失败,请刷新页面

加载更多

我最喜欢的Mybatis 3.5新特性——Optional支持

Mybatis 3.5 发布有段时间了,终于支持了 Optional ,这么实用的特性,竟然还没人安利……于是本文出现了。 文章比较简单,但非常实用,因为能大量简化恶心的判空代码。 WARNING 由于本文非常...

周立_ITMuch
20分钟前
5
0
Android 开发工具推荐

简评: 自己过去在 Android 开发中发现的好工具,在这里分享给大家。: ) Library methods count 每一个 Android App 的开发中都会用到很多的库,这个工具能够让你看到不同库的大小和,帮助你...

极光推送
20分钟前
0
0
高并发解决方案

我们通常衡量一个Web系统的吞吐率的指标是QPS(Query Per Second,每秒处理请求数),解决每秒数万次的高并发场景,这个指标非常关键。举个例子,我们假设处理一个业务请求平均响应时间为100...

孤狼悲月
26分钟前
1
0
Kubernetes 中的渐进式交付:蓝绿部署和金丝雀部署

本文首发于:Jenkins 中文社区 渐进式交付是持续交付的下一步, 它将新版本部署到用户的一个子集,并在将其滚动到全部用户之前对其正确性和性能进行评估, 如果不匹配某些关键指标,则进行回...

Jenkins中文社区
31分钟前
4
0
大数据辟谣:布洛芬用药不慎可能致死?如此标题党居心何在

相信很多人看到一则“布洛芬用药不慎可能致死”的消息后,内心开始慌乱了。 (新闻来源:微博热搜排行榜) 毕竟健康是每一个人最关注的话题,而布洛芬也是很多人止痛(发烧头痛、喉咙痛、牙痛...

forespider
35分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部