1. 程式人生 > >序列化與反序列化技術選型

序列化與反序列化技術選型

文章目錄

一、使用場景

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" : { }
}