对象在网络中传输

491 阅读3分钟

为什么需要序列化?

网络传输的数据必须是二进制数据,但是调用方请求的出入参数都是对象.对象不能直接在网络中传输,所以我们需要提前把它转成可传输的二进制,并且要求转化算法是可逆的,这个过程我们一般叫做"序列化".

网络传输的数据必须是二进制数据,所以在RPC调用中,对入参对象与返回值对象进行序列化与反序列化是一个必须的过程.

常用的序列化

JDK原生序列化

序列化具体的实现是 由 ObjectOutputStream 完成的,而反序列化的具体实现是由 ObjectInputStream 完成 的

序列化过程就是在读取对象数据的时候,不断加入一些特殊分隔符,这些特殊分隔符用于在 反序列化过程中截断用.

头部数据用来声明序列化协议、序列化版本,用于高低版本向后兼容

对象数据主要包括类名、签名、属性名、属性类型及属性值,当然还有开头结尾等数 据,除了属性值属于真正的对象值,其他都是为了反序列用的元数据

实际上任何一种序列化框架,核心思想就是设计一种序列化协议.


JSON

K-V方式,没有数据类型,是一种文本型序列化框架

问题:

1. JSON序列化而外空间开销大,对于大数据量服务需要巨大的内存和磁盘开销

2. JSON没有类型,JAVA强类型语言需要通过反射解决,性能差

Hessian

Hessian是动态类型\二进制\紧凑的,并且可跨语言移植.

协议比JDK\JSON更加紧凑,性能比JDK\JSON序列化高效,生成的字节数更小

问题:

1. 官方版本对Java里面一些常见对象类型不支持,比如:

Linked 系列,LinkedHashMap、LinkedHashSet 等,但是可以通过扩展 CollectionDeserializer 类修复;

Locale 类,可以通过扩展 ContextSerializerFactory 类修复;

Byte/Short 反序列化的时候变成 Integer.

Protobuf

Google内部混合语言数据标准,是一种轻便\高效的结构化数据存储格式,可支持Java\Python\C++\Go等语言,使用前需要定义IDL(Interface description language),然后使用不同语言的IDL编译器,生成序列化工具类.

优点:

1. 序列化体积小

2. IDL能清晰地描述语义,保证应用程序之间的类型不会丢失,无需类似XML解析器

2. 序列化反序列化速度快,不需要通过反射获取类型

4. 消息格式升级和兼任性不错,可以做到向后兼容

如何选择序列化协议?

总结

服务调用的稳定性与可靠性,要比服务的性能与响应耗时更加重要。另 外对于 RPC 调用来说,整体调用上,最为耗时、最消耗性能的操作大多都是服务提供者执 行业务逻辑的操作,这时序列化的开销对于服务整体的开销来说影响相对较小.


在使用RPC框架过程中,我们构造入参\返回值对象,注意点:

1. 对象要尽量简单,没有太多的依赖关系,属性不要太多,尽量高内聚

2. 入参对象与返回值对象体积不要太大,更不要传太大的集合

3. 尽量使用简单的\常用的\开发语言原生的对象,尤其是集合类

4.对象不要有复杂的继承关系,最好不要有父子类的情况