调用dubbo接口并对返回对象进行序列化,结果不是我想的那样,为什么&怎么办?
故事案例:
(以下称dubbo服务提供方为“平台”,dubbo服务调用方为“业务”)
问题定位:
1、现象:调用平台的这个类com.x.api.service.UserApiService 的这个接口,得到的是一个list结果集,对结果集用alibaba 的fastjson 序列化成字符串的时候就有问题了。
2、问题原因:
平台开发在改动旧接口时,有个地方赋值的时候没有new一个新的对象,导致List里会重复引用之前的对象。
单从dubbo接口返回的数据看是没有问题的,平台测试只校验了返回数据的正确性,没关注是否存在重复引用。
业务开发调用接口后使用的是FastJson序列化方式,“fastjson序列化的对象中,若存在重复引用的情况,序列化的结果可能不是我们预期的结果”
3、解决办法:
平台开发——避免重复引用;
业务开发——关闭循环引用检测参数,JSON.toJSONString(res, SerializerFeature.DisableCircularReferenceDetect);
平台测试——在测试代码中模拟业务方的序列化操作,可提前发现此类问题。
问题分析:
Dubbo作为一个扩展能力极强的分布式服务框架,在实现rpc特性的时候,给序列化方式提供了多种(Hessian2、dubbo、JSON(fastjson实现)、JAVA、SOAP、kryo和fst 等)扩展实现,供业务开发者根据实际场景进行选择。(各种序列化方式的实现——深入理解 RPC 之序列化篇 -- 总结篇)
Q1:dubbo服务消费方在序列化使用时可能会遇到哪些坑?(可以总结经验,共享给各个业务方)
答:
●“重复引用,序列化的结果往往不是我们预期的”,可以通过关闭循环引用检测参数的方法从业务端解决。(案例中的问题点即是该问题)。FastJson 反序列化注意事项 中还提到了其他可能的问题。
●如果用的是Hessian2序列化方式,可能会遇到的问题有浮点数反序列化问题、子类覆盖父类字段hession反序列化获取不到
●ArrayList的子类在进行序列化时丢失属性的问题,可以通过对序列化类CollectionSerializer进行修改,同步修改相应的反序列化类解决问题
●Dubbo Hessian序列化参数为NULL问题,dubbo在采用hessian序列化时,一定要注意子类和父类不能有同名字段
●在使用dubbo时,HashMap不能作为Serializable的实例
小结:使用方在使用某种序列化方式时,应该了解该方式的特性,并考虑相关问题。比如,循环引用会不会出现问题 等等等等….
Q2:dubbo服务提供方在接口兼容性升级的时候有什么可以改进的地方?
答:
Q3:平台测试能做些什么?
答:
序列化性能分析与测试、dubbo典型协议、序列化方式组合性能对比测试——“在做性能分析和测试的时候我们并不单独处理每种序列化方式,而是把它们放到dubbo RPC中加以对比,因为这样更有现实意义。”
了解现在各个业务方的序列化方式,评估在测试代码中模拟哪种序列化操作(RPC为了追求可扩展性、性能等诸多因素,会支持多种序列化方式,测试时需要覆盖适当常用的序列化方式)
在测试代码中模拟业务的序列化操作(举例如下)
/***序列方式一:用 alibaba 的 fastjson **/
//在pom中添加依赖
<dependency>
com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.31</version>
</dependency>
//
import com.alibaba.fastjson.JSON;
// List 转 json string
String jsonStr = JSON.toJSONString( list );
// Map 转 json string
String jsonStr = JSON.toJSONString( map );