RPC调用msgpack序列化问题分析

作者:Alan

时间:2020年6月11日星期四

微信:wei_wei10

问题:

线上业务异常,调用方反馈JSF服务RPC调用异常。读取服务列表服务,所有服务编码均为0(service_code:0)

 

问题分析:

迅速回滚线上代码,立即止损。在CodeReview过程中,发现API接口中的一个参数属性有变化,JSF 的接口jar做了升级。

 

这个参数继承了一个父VO,这个父VO增加了一个新的字段(+ statue:int)。JSF的序列化方式为msgpack。业务方未同步更新JSF接口jar包,导致了JSF 反序列化的异常。

 

RPC调用msgpack序列化问题分析

 

为什么反序列化会失败?这个和msgpack有关系。

 

咱先来看msgpack的官方定义(官网:https://msgpack.org/):

 

MessagePack is an efficient binary serialization format. It lets you exchange data among multiple languages like JSON. But it's faster and smaller. Small integers are encoded into a single byte, and typical short strings require only one extra byte in addition to the strings themselves.

 

从官方定义中可以得出以下结论:

  1. 首先它是一种二进制序列化格式。
  2. 它允许跨语言交换数据。
  3. 性能上,它比json序列化性能要好。
  4. 体积上,它比json序列化体积要小。

 

以上是msgpack的优点,但是在接受它的优点的同时,必须同时接受它的缺点。

其中一个缺点是无法改变字段顺序

 

对,无法改变字段顺序。线上JSF调用,反序列化异常就是因为这个原因。序列化的对象,顺序被改变了。

 

我找来了一个官方的一个示例说明,这个例子里解释了为什么序列化后内容体积会变小。

 

RPC调用msgpack序列化问题分析

 

可以看到,msgpack序列化结果,只有value!并且value进行了专属映射。

(官方说明书:https://github.com/msgpack/msgpack/blob/master/spec.md

 

再来个直观对比:

 

RPC调用msgpack序列化问题分析

RPC调用msgpack序列化问题分析

 

 

msgpack是不是让人又爱又恨。选用msgpack就是为了效率,咱来了解一下兼容规则。

 

在两边不同时升级的情况下,字段兼容规则如下:

  1. 不能调整原有字段顺序,不能删减字段。最后一个字段除外。
  2. 新增的字段必须在字段最后。
  3. 父类字段不能改变,因为父类改变等于在子类中间插入了一个字段。

 

如果违反上面????任意一条,必须RPC客户端与服务器同时升级。