dubbo反序列化异常导致服务负载飙高、吞吐率下降

发现问题

如果consumer端的pojo对象的版本号低于provider端,provider端返回consumer端不存在的pojo对象。dubbo默认用hession在consmer端反序列化时,会抛出一个warning的异常。如图:

看了下dubbo源码,发现hession在反序列化,调用Class.ForName(type, false, classLoader)失败时会抛出此异常warning。这里hession会兼容这个异常,返回空。而不像kryo等其他序列化工具那样直接返回请求失败。所以大家最好不要轻易更换dubbo序列化工具,默认选择hession,dubbo肯定是考虑的多方面的因素。这里抛出的这个异常说明在consumer端当前线程的classloader中没有这个pojo对象。

这里注意下如果Class.ForName(type, false, classLoader)反射正常,dubbo会将反序列化的对象cache起来。即反射只会执行一次,后续同样type的请求走缓存。但是如果反射失败,每次请求都会执行Class.ForName(type, false, classLoader)。说到这里大家应该知道了为啥服务飙高、吞吐率下降了吧。

解决方案

定位了问题,那么逆向思考,只要保证在反序列化发生异常时反射也只发生一两次,服务的负载就不会飙高,吞吐率也不会下降。所以在反射失败时动态想classloader创建一个空的pojo class,或者在dubbo缓存的map中,针对当前type指定一个占位符,即可解决问题 

示例代码

这里用到了javassist创建动态的type类型的代理对象,在ctClass.toClass()放入当前线程的classloader后,重新反序列化一次,这样dubbo就会将type类型的反序列化对象cache起来。
dubbo默认是使用Hessian2SerializerFactory做序列化工作,那么如何用自定义的Hessian2SerializerFactoryExtension扩展对象替换下默认的Hessian2SerializerFactory呢?继续翻源码,发现所有的序列化实现都被dubbo缓存到CodecSupport.java的ID_SERIALIZATION_MAP中了,那么我只需要获取到这个map,用Hessian2SerializerFactoryExtension覆盖Hessian2SerializerFactory即可。

参考代码地址:https://github.com/qinpeirong0011/dubbox/tree/2018-01-18-qinpr

原文地址:https://qinpeirong0011.github.io/2019/01/21/hession%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%BC%82%E5%B8%B8/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值