本篇主要就序列化的認(rèn)識進(jìn)行說明,不就某種序列化方式進(jìn)行深入。
什么是序列化?
??????序列化對于大部分開發(fā)人員是一個熟悉又遙遠(yuǎn)的詞,我們經(jīng)常要用到序列化,但是又不清楚為什么要序列化。我們以Java提供的序列化機(jī)制為例,它可以將對象的狀態(tài)信息轉(zhuǎn)變?yōu)槎M(jìn)制數(shù)據(jù),實(shí)際上這個過程就是將內(nèi)存中的數(shù)據(jù)轉(zhuǎn)換為某種可持久化或者可傳輸?shù)母袷降倪^程。這也是序列化的過程,反之反序列化則是將數(shù)據(jù)重新讀入內(nèi)存的過程。
為什么需要序列化?
??????這個問題也是大多數(shù)人最想知道的一個問題,同樣我還是以Java為例,我們知道,Java程序的運(yùn)行時(shí)依賴于JVM的,只有jvmJVM的時(shí)候,對象才可能存在(這里說的對象是內(nèi)存中的對象,而非以某種形式持久化存在的),也就是說對象的生命周期是不會超過JVM生命周期的,但是我們往往需要希望能夠在JVM停止運(yùn)行后保存對象的狀態(tài),以便在別的地方使用。這也是序列化的第一個作用,將對象字節(jié)序列持久化。
??????對于現(xiàn)在的大多數(shù)應(yīng)用來說,都是網(wǎng)絡(luò)應(yīng)用,那么這就需要進(jìn)行網(wǎng)絡(luò)傳輸,我們知道,對象是存在于內(nèi)存中的,顯然是無法進(jìn)行網(wǎng)絡(luò)傳輸?shù)模晕覀冃枰砸环N方式來傳輸對象,這也是序列化的第二個作用。
總結(jié):序列化實(shí)際上是為了讓內(nèi)存中的對象或者數(shù)據(jù)結(jié)構(gòu)以一種可以存儲和傳輸?shù)母袷酱嬖凇?/em>
序列化的方式
序列化的方式主要是兩種,文本方式與二進(jìn)制方式,如何進(jìn)行選擇也是很重要的一點(diǎn),我主要考慮以下方面,
- 通用性
序列化機(jī)制在一定程度上要能夠彌補(bǔ)OS之間的差異,方便進(jìn)行傳輸,所以在選擇序列化協(xié)議的時(shí)候,我們會考慮是否支持跨平臺、跨語言。如果不支持,在技術(shù)層面上的通用性就大大降低了。例如Java本身提供的serialization機(jī)制無法在非JVM平臺上使用,限制了它的通用性。如果我們要在不同的編程語言之間傳遞對象,就必須把對象序列化為標(biāo)準(zhǔn)格式,比如XML,但更好的方法是序列化為JSON,因?yàn)镴SON表示出來就是一個字符串,可以被所有語言讀取,也可以方便地存儲到磁盤或者通過網(wǎng)絡(luò)傳輸。 - 安全性 / 訪問限制
考慮到對外提供接口的兼容性,我們通常會采用REST+JSON的方案,用于內(nèi)網(wǎng)通信的RPC通常使用二進(jìn)制方式序列化,因?yàn)榫W(wǎng)絡(luò)中只有字符串可以穿透防火墻,HTTP位于應(yīng)用層,跨防火墻,可以在不同的局域網(wǎng)之間通信,而HTTP本身是一個文本協(xié)議,雖然可以傳輸二進(jìn)制數(shù)據(jù),但是通常需要經(jīng)過BASE64或者M(jìn)IME編碼(HTTP2支持二進(jìn)制流),所以會選擇兼容性更好以及本身就是文本格式的JSON或者XML。對于RPC來說,RPC 使用TCP協(xié)議位于傳輸層,TCP是一種二進(jìn)制協(xié)議,對二進(jìn)制數(shù)據(jù)提供天然的支持,并且大多是用于內(nèi)網(wǎng)通信,所以會選擇效率更好的二進(jìn)制序列化方式(關(guān)于傳輸協(xié)議:不同之處在于協(xié)議是圍繞數(shù)據(jù)結(jié)構(gòu)還是圍繞文本字符串)。
從安全性的角度考慮,二進(jìn)制協(xié)議很方便進(jìn)行加密,防止協(xié)議被破解,從而保護(hù)了傳遞的信息,增加協(xié)議破解的難度,而文本協(xié)議方便解讀,并不適合進(jìn)行加密。 - 可擴(kuò)展性/兼容性
以JSON和XML為主的文本格式,如果需要增加一些條件,直接添加Key和Value就可以了,擴(kuò)展方便,而二進(jìn)制數(shù)據(jù)如果修改已有字段的順序就會造成消息無法正確解析。
二進(jìn)制序列化的數(shù)據(jù)因?yàn)槭菄?yán)格的內(nèi)存到對象的轉(zhuǎn)換,所以要求發(fā)送方與接收方的的機(jī)器字節(jié)序保持一致,否則無法正確解析。而文本格式的數(shù)據(jù)對于消息的發(fā)送方和接收方的采用的編程語言沒有嚴(yán)格的限制,對于多語言編寫提供了便利。
- 性能
空間開銷(Verbosity), 序列化需要在原有的數(shù)據(jù)上加上描述字段,以為反序列化解析之用。二進(jìn)制數(shù)據(jù)只保存了必須的信息,在需要傳遞大量信息的時(shí)候,對于磁盤和帶寬的節(jié)省是非常明顯的。而對于JSON和XML而言,因?yàn)榇嬖诖罅棵枋鲂缘男畔?,進(jìn)行序列化的額外空間開銷比較大,對于大數(shù)據(jù)量服務(wù)或持久化,這意味著巨大的內(nèi)存和磁盤開銷。
時(shí)間開銷(Complexity),以Java為例,某些序列化方式需要依賴反射,往往會導(dǎo)致比較長時(shí)間的解析時(shí)間,這可能會成為應(yīng)用的瓶頸。
- 可讀性
序列化后的二進(jìn)制數(shù)據(jù)往往不具備人眼可讀性,為了驗(yàn)證序列化結(jié)果的正確性,寫入方不得同時(shí)撰寫反序列化程序,如果序列化后的數(shù)據(jù)人眼可讀,這將大大提高調(diào)試效率, XML 和 JSON 就具有人眼可讀的優(yōu)點(diǎn)。
參考文獻(xiàn):
https://www.infoq.cn/article/serialization-and-deserialization
http://cn.voidcc.com/question/p-prmzkbxa-mb.html
https://www.liaoxuefeng.com/wiki/1016959663602400/1017624706151424
https://studygolang.com/articles/7855
https://hhbbz.github.io/2017/06/25/%E4%BB%8EDubbo%E6%B5%85%E8%B0%88RPC%E5%92%8CHTTP/