作者:Alan jiang |
时间:2020年6月11日星期四 |
微信:wei_wei10 |
问题:
线上业务异常,调用方反馈JSF服务RPC调用异常。读取服务列表服务,所有服务编码均为0(service_code:0)
问题分析:
迅速回滚线上代码,立即止损。在CodeReview过程中,发现API接口中的一个参数属性有变化,JSF 的接口jar做了升级。
这个参数继承了一个父VO,这个父VO增加了一个新的字段(+ statue:int)。JSF的序列化方式为msgpack。业务方未同步更新JSF接口jar包,导致了JSF 反序列化的异常。
为什么反序列化会失败?这个和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.
从官方定义中可以得出以下结论:
- 首先它是一种二进制序列化格式。
- 它允许跨语言交换数据。
- 性能上,它比json序列化性能要好。
- 体积上,它比json序列化体积要小。
以上是msgpack的优点,但是在接受它的优点的同时,必须同时接受它的缺点。
其中一个缺点是无法改变字段顺序。
对,无法改变字段顺序。线上JSF调用,反序列化异常就是因为这个原因。序列化的对象,顺序被改变了。
我找来了一个官方的一个示例说明,这个例子里解释了为什么序列化后内容体积会变小。
可以看到,msgpack序列化结果,只有value!并且value进行了专属映射。
(官方说明书:https://github.com/msgpack/msgpack/blob/master/spec.md)
再来个直观对比:
msgpack是不是让人又爱又恨。选用msgpack就是为了效率,咱来了解一下兼容规则。
在两边不同时升级的情况下,字段兼容规则如下:
- 不能调整原有字段顺序,不能删减字段。最后一个字段除外。
- 新增的字段必须在字段最后。
- 父类字段不能改变,因为父类改变等于在子类中间插入了一个字段。
如果违反上面👆任意一条,必须RPC客户端与服务器同时升级。