序列化與反序列化技術選型
文章目錄
一、使用場景
1、網路傳輸
2、加密、持久化
二、概念
1、通訊協議中的位置
七層模型的表示層或者四層模型的應用層
2、概念
序列化 : 資料結構或者物件 -> 二進位制
反序列化 : 二進位制 -> 資料結構或者物件
注:二進位制串 儲存在記憶體中的一塊資料, C++的字串、 Java的byte[]陣列
三、參考指標
每種序列化協議都有優點和缺點,它們在設計之初有自己獨特的應用場景。在系統設計的過程中,需要考慮序列化需求的方方面面,綜合對比各種序列化協議的特性,最終給出一個折衷的方案。
1、通用性
(1) 是否跨平臺, 跨語言
(2) 協議是否成熟, 是否流行, 使用人數多少
2、可讀性/可除錯性
(1) 提高開發效率
(2) 便於排查問題(支援不到位、訪問限制)
3、效能
(1) 空間開銷
(2) 時間開銷
4、可擴充套件性/相容性
具有良好的可擴充套件性, 支援自動增加新的業務欄位, 而不影響老的服務, 這將大大提供系統的靈活度
5、安全性/訪問控制
協議與埠限制 : http&https協議、80&443埠
(1) 因訪問限制而降低服務可用性
(2) 重新實現安全協議而導致提高實施成本
(3) 開放更多的防火牆埠和協議訪問, 降低安全性
四、序列化與反序列化協議
通用元件
IDL(Interface description language)檔案 : 參與通訊的各方需要對通訊的內容需要做相關的約定, 該約定於語言無關, 與平臺無關
IDL Complier : IDL檔案中約定的內容為了在各語言和平臺可見,需要有一個編譯器,將IDL檔案轉換成各語言對應的動態庫
Client/Server : 指的是應用層程式程式碼,他們面對的是IDL所生存的特定語言的class或struct
Stub/Skeleton Lib : 負責序列化和反序列化的工作程式碼
底層協議棧和網際網路 : 序列化之後的資料通過底層的傳輸層、網路層、鏈路層以及物理層協議轉換成數字訊號在網際網路中傳遞
流程圖
待序列化類
class Address {
private String city;
private String postcode;
private String street;
}
public class UserInfo {
private Integer userid;
private String name;
private List<Address> address;
}
XML
(1) 基於http協議可穿透防火牆, 可讀性高
(2) 空間開銷大, 時間開銷大
(3) 適合實時性要求較低(例如秒級)的服務
<xsd:complexType name='Address'>
<xsd:attribute name='city' type='xsd:string' />
<xsd:attribute name='postcode' type='xsd:string' />
<xsd:attribute name='street' type='xsd:string' />
</xsd:complexType>
<xsd:complexType name='UserInfo'>
<xsd:sequence>
<xsd:element name='address' type='tns:Address'/>
<xsd:element name='address1' type='tns:Address'/>
</xsd:sequence>
<xsd:attribute name='userid' type='xsd:int' />
<xsd:attribute name='name' type='xsd:string' />
</xsd:complexType>
### JSON
(1) 基於http協議可穿透防火牆, 可讀性高, 空間開銷比XML(1/2)小, 解析時間開銷比XML小, 基於關聯陣列的實現有更好的可擴充套件性和相容性
(2) 一定的空間消耗, 不適合持久化儲存; 沒有統一的IDL約束, 給除錯帶來麻煩; 在一些語言中需要反射來實現序列化和反序列化, 增加時間消耗。
(3) 適合實時性要求較低(如秒級), 資料量傳輸較少的服務; 基於web browser的ajax請求; 介面經常變動, 可除錯性要求較高的服務。
{"userid":1,"name":"messi","address":[{"city":"北京","postcode":"1000000","street":"wangjingdonglu"}]}
Thrift
(1) 支援多種語言; 支援RPC呼叫
(2) Thrift的序列化被嵌入到Thrift框架裡面, 很難和其他傳輸層協議共同使用(Http); 文件缺乏, 學習成本高; 資料格式為二進位制, 可讀性差; 序列化與框架緊耦合, 無法實現持久化功能
(3) 適合實時性要求較高的大資料量、分散式、跨平臺、跨語言的服務
struct Address {
1: required string city;
2: optional string postcode;
3: optional string street;
}
struct UserInfo {
1: required string userid;
2: required i32 name;
3: optional list<Address> address;
}
Protobuf
(1) IDL和IDL編譯器對工程師友好; 空間開銷小(約為XML的1/3到1/10); 時間開銷小(約為XML的20到100倍); 純粹的序列化協議, 可與各種傳輸層協議結合使用; 文件非常完善
(2) 支援的資料型別相對較少; 不支援RPC框架
(3) 適合公司內實時性要求較高的服務; 可與http協議結合, 穿透防火牆, 適合公司間對效能要求較高的場景; 解析效能高, 序列化資料量少, 適合持久化
message Address{
required string city=1;
optional string postcode=2;
optional string street=3;
}
message UserInfo{
required string userid=1;
required string name=2;
repeated Address address=3;
}
Avro
(1) 兩種序列化格式JSON和二進位制; 二進位制的空間開銷和時間開銷媲美Protobuf; 支援資料型別豐富; 支援JSON格式的IDL和類似Thrift和Protobuf的IDL; 持久化連同Schema一起儲存, 對Hive Pig Hadoop具有親和力; 具有向前相容與向後相容的特性; IDL Schema支援動態載入, 支援程式中動態編譯Schema
(2) JSON格式的IDL對於習慣於靜態型別語言的工程師來說不直觀
(3) 適合公司內實時性要求較高的服務; 可與http協議結合, 穿透防火牆, 適合公司間對效能要求較高的場景; 解析效能高, 序列化資料量少, 適合持久化
IDL檔案:
protocol Userservice {
record Address {
string city;
string postcode;
string street;
}
record UserInfo {
string name;
int userid;
array<Address> address = [];
}
}
IDL JSON Schema 檔案:
{
"protocol" : "Userservice",
"namespace" : "org.apache.avro.ipc.specific",
"version" : "1.0.5",
"types" : [ {
"type" : "record",
"name" : "Address",
"fields" : [ {
"name" : "city",
"type" : "string"
}, {
"name" : "postcode",
"type" : "string"
}, {
"name" : "street",
"type" : "string"
} ]
}, {
"type" : "record",
"name" : "UserInfo",
"fields" : [ {
"name" : "name",
"type" : "string"
}, {
"name" : "userid",
"type" : "int"
}, {
"name" : "address",
"type" : {
"type" : "array",
"items" : "Address"
},
"default" : [ ]
} ]
} ],
"messages" : { }
}