Java 序列化与主流编解码技术框架介绍

本文导读

     本文将主要介绍:1)Java 序列化的缺点,2)业界流行的编解码技术框架介绍。

     介绍编解码技术之前,就不得不提 Java 序列化,记住:Java 序列化只是 Java 编解码技术中的其中一种!

     Java 序列化的目的主要有两点:

     1)网络传输

     2)对象持久化

     基于 Java 提供的对象输入/输出流 ObjectInputStream 和 ObjectOutputStream ,可以直接把 Java 对象作为可存储的字节数组写入文件,也可以在网络上传输。这对于程序员来说,通过基于 JDK 默认的序列化机制可以避免操作底层的字节数组,从而提升开发效率。

     网络传输时,需要把传输的 Java 对象编码为字节数组或者 ByteBuffer 对象,而当远程服务读取到 ByteBuffer 对象或者字节数组时,需要再将其解码成发送时的 Java 对象,这就称为 Java 对象编解码技术

Java 序列化的缺点

     Java 序列化从 JDK1.1 版本就已经提供,它不需要添加额外的类库,最简单的方式只需要实现 java.io.Serizlizable 接口即可。 可以参考《Java 序列化漏洞多到修不完》、《Java 内置序列化三种方式

1)无法跨语言传输

     无法跨语言是 Java 序列化最致命的问题。对于跨进程的服务调用,服务提供者可能会使用 C++ 等其它语言开发,而当需要和异构语言进程交互时,Java 序列化就难以胜任。

     由于 Java 序列化技术是 Java 语言内部的私有协议,其它语言并不支持,对于用户来说它完全是黑盒。Java 序列化后的字节数组,别的语言无法进行反序列化,这就严重阻碍了它的应用。

     目前市场上流行的 Java RCP(远程服务调用)通信框架,都没有使用 Java 序列化作为编解码框架,原因就是它无法跨语言。

2)序列化后码流过大

      评价一个编解码框架的优劣时,往往会考虑以下因素:

     ** 是否支持跨语言,支持的语言种类是否丰富

     ** 编码后的码流大小

     ** 编解码的性能

     ** 类库是否小巧,API 使用是否方便

     ** 使用者需要手工开发的工作量和难度

     同等情况下,编码后的字节数组越大,存储的空间就越大,硬盘成本就越高,网络传输时越占宽带,导致系统的吞吐量降低。Java 序列化后的码流偏大也一直被业界所诟病,导致应用范围受到了很大限制。

3)序列化性能太低

     比如相比其它方式,同样是序列化 100万次,Java 序列化耗费时间长。

主流编解码框架

       Java 序列化仅仅是 Java 编解码技术的一种,由于它的种种缺陷,于是业界开发出了多种性能更优秀的编解码技术框架,本文会选择其中主流编解码技术框架进行介绍,看看如何在 Netty 中应用这些编解码框架实现消息的高效序列化。

Google 的 Protobuf

      Protobuf 全称 Google Protocol Buffers,由谷歌开源而来,在谷歌内部久经考验。它将数据结构以 .proto 文件进行描述,通过代码生成工具可以生成对应数据结构的 POJO 对象和 Protobuf 相关的属性和方法。

     Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据序列化。它很适合做数据存储或 RPC 数据交换。

      Protobuf 在 Github 开源地址https://github.com/protocolbuffers/protobuf

     Protobuf supports several different programming languages. For each programming language, you can find instructions in the corresponding source directory about how to install protobuf runtime for that specific language:

Language Source Ubuntu MacOS Windows
C++ (include C++ runtime and protoc) src Build status Build status Build status
Build status
Build status
Java java Build status
Build status
Build status
   
Python python Build status
Build status
Build status
Build status
Build status
 
Objective-C objectivec   Build status
Build status
Build status
Build status
 
C# csharp Build status   Build status
JavaScript js Build status Build status  
Ruby ruby Build status
Build status
Build status
Build status
Build status
Build status
 
Go golang/protobuf      
PHP php Build status
Build status
Build status
Build status
 
Dart dart-lang/protobuf Build Status    

     Protobuf 另一个吸引人的是它的数据描述文件和代码生成机制。利用数据描述文件对数据结构进行说明,其优点如下:

1)文本话的数据结构描述语言,可以实现语言和平台无关,特别适合异构系统间的集成

2)通过标识字段的顺序,可以实现协议的前后兼容

3)字段代码生成,不需要手工编写同样数据结构的 C++ 和 Java 版本

4)方便后续的管理和维护,相比于代码,结构化的文档更易管理和维护

Facebook 的 Thrift

     Thrift 源于 Facebook,创建的目的是为了解决 Facebook 各系统间大数据量的传输通信问题,满足系统之间语言环境不同的需求。Thrift 可以支持多种程序语言:

     The Apache Thrift software framework, for scalable cross-language services development, combines a software stack with a code generation engine to build services that work efficiently and seamlessly between C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, OCaml and Delphi and other languages.

     2007 年 Facebook 将 Thrift 作为一个开源项目提交给 Apache 基金会,Apache Thrift 官网地址http://thrift.apache.org/

     在多种不同的语言之间通信,Thrift 可以作为高性能的通信中间件使用,它支持数据(对象)序列化和多种类型的 RPC 服务。Thrift 适用于静态的数据交换,需要先确定好它的数据结构,当数据结构发生变化时,必须重新编辑 IDL 文件,生成代码和编译,这一点和其它 IDL 工具相比是  Thrift 的弱项。Thrift 适用于搭建大型数据交换及存储的使用工具,对于大型系统中的内部数据传输,相比于 JSON 和 XML 在性能和传输大小上都有明显的优势。

     Thrift 主要由 5 部分组成:

1)语言系统以及 IDL 编译器:负责由用户给定的 IDL 文件生成相应语言的接口代码;

2)TProtocol:RPC 的协议层,可以选择多种不同的对象序列化方式,如 JSON 和 Binaru;

3)TTransport:RPC 的传输层,同样可以选择不同的传输层实现,如 Socket、NIO、MemoryBuffer 等;

4)TProcessor:作为协议层和用户提供的服务实现之间的纽带,负责调用服务实现的接口;

5)TServer:聚合 TProtocol、TTransport、TProcessor 等对象。

     对于编解码框架,与之对应的就是 TProtocol 。由于 Thrift 的 RPC 服务调用和编解码框架绑定在一起,所以通常使用 Thrift 的时候会采取  RPC 框架的方式,但是它的 TProtocol 编解码框架还是可以以类库的方式独立使用的。

     Thrift 通过 IDL 描述接口和数据结构定义,它支持Java 8 种基本类型、Map、List、Set,支持可选和必选定义,功能非常强大。因此可以定义数据结构中的字段的顺序,可以支持协议的前向兼容。

     Thrift 支持三种比较典型的编解码方式:

1)通用的二进制编解码

2)压缩的二进制编解码

3)优化的可选字段压缩编解码

     由于支持二进制压缩编解码,所以 Thrift 的编解码性能表现也相当优异,远远超过 Java 序列化和 RMI 等。

Jboos 的 Marshaling

     JBoss Marshalling 是一个 Java 对象的序列化 API 包,修正了 JDK 自带的序列化包的很多问题,但又保持跟 java.io.Serializable 接口的兼容。同时增加了一些可调的参数和附加的特性,并且这些参数和特性可通过工厂类进行配置。

     JBoss Marshalling 官网地址:http://jbossmarshalling.jboss.org/

     Marshalling 在 GitHub 开源地址:https://github.com/jboss-remoting/jboss-marshalling

     相比于传统的 Java 序列化机制,Marshalling 的优点如下:

1)可插拔的类解析器,提供更加便捷的类加载定制策略,通过一个接口即可实现定制;

2)可插拔的预定义类缓存表,可以减小序列化的字节数组的长度,提升常用类型的对象序列化性能;

3)无需再实现 java.io.Serializable 接口,即可实现 Java 序列化;

4)通过缓存技术提升对象的序列化性能。

MessagePack

It's like JSON.but fast and small.

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,但是更快更小。
MessagePack 是一种高效的二进制序列化格式。它允许您在 JSON 等多种语言之间交换数据,但它更快速更小巧。小整数被编码为单个字节,典型的短字符串除了字符串本身之外只需要一个额外的字节。

MessagePack 官网地址:https://msgpack.org/

MessagePack GitHub 开源地址:https://github.com/msgpack/msgpack

MessagePack Java 模块 GitHub 开源地址:https://github.com/msgpack/msgpack-java

核心压缩方式可参看官方说明:https://github.com/msgpack/msgpack/blob/master/spec.md

MessagePack is supported by over 50 programming languages and environments.(MessagePack 支持主流的 50 多种编程语言)

猜你喜欢

转载自blog.csdn.net/wangmx1993328/article/details/84429134