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 序列化漏洞多到修不完
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 | |||
Java | java | |||
Python | python | |||
Objective-C | objectivec | |||
C# | csharp | |||
JavaScript | js | |||
Ruby | ruby | |||
Go | golang/protobuf | |||
PHP | php | |||
Dart | dart-lang/protobuf |
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 多種程式語言)