1. 为何需要序列化
- 网络传输都是二进制数据,在进行RCP调用时,我们需要将对象数据转化成二进制格式,同时这种转换也需要可逆,将二进制数据恢复成程序可调用数据,即反序列化。
- 可以方便地在不同格式和媒介下持久化,比如把一个对象里的内容保存成文件,或是存入缓存,etc。
- 保证数据的安全性和完整性,比如通信协议消息格式固定,但是序列化后的数据,不知道协议规则的话便无法破解消息内容,从某种意义上保障了数据的安全性和完整性。---自己的理解。
- 方便深度拷贝,在日常编代码时,常用到beanUtils的copy,把一个复杂对象进行copy时,我们就直接用JSON的序列化和反序列化了,很便捷。
2. 常见的序列/反序列化方式
JDK(不支持跨语言)、JSON、XML、Hessian、Kryo(不支持跨语言)、Thrift、Protostuff(基于Protobuf)、FST(不支持跨语言)
常见RCP框架中,dubbo和thrift的序列化协议都可以扩展,gRPC及bRPC都使用了Protobuf
3. 序列化协议选型的考虑点
以下重要性依次递减
- 安全性
- 通用性:关系到服务的可靠性
- 兼容性:关系到服务的可靠性
- 性能:关系到RPC框架整体的性能
- 效率:关系到RPC框架整体的效率
- 空间开销:网络传输数据越小,传输就越快
我们更加看重这种序列化协议在版本升级后的兼容性是否很好,是否支持更多的对象类型,是否是跨平台、跨语言的,是否有很多人已经用过并且踩过了很多的坑,其次我们才会去考虑性能、效率和空间开销。
综合上面几个参考因素,现在我们再来总结一下这几个序列化协议。我们首选的还是 Hessian 与 Protobuf,因为他们在性能、时间开销、空间开销、通用性、兼容性和安全性上,都满足了我们的要求。其中 Hessian 在使用上更加方便,在对象的兼容性上更好;Protobuf 则更加高效,通用性上更有优势。
4. 设计RCP传输对象的注意点
在使用 RPC 框架的过程中,我们构造入参、返回值对象,主要记住以下几点:
- 对象要尽量简单,没有太多的依赖关系,属性不要太多,尽量高内聚;
- 入参对象与返回值对象体积不要太大,更不要传太大的集合;
- 尽量使用简单的、常用的、开发语言原生的对象,尤其是集合类;
- 对象不要有复杂的继承关系,最好不要有父子类的情况。
* 此文参考了网络部分文章及极客时间课程《RPC实战与核心原理|03序列化》