啃論文俱樂部---JSON壓縮算法解讀

??想了解更多關(guān)于開源的內(nèi)容,請訪問:??
JSON壓縮算法解讀
接下來我們進(jìn)入關(guān)于JSON壓縮算法的學(xué)習(xí)。
為什么需要壓縮JSON?
盡管JSON數(shù)據(jù)格式比XML效率要高,但是它仍然是web服務(wù)器和瀏覽器傳輸過程中比較低效的數(shù)據(jù)格式。為什么呢?首先,它將所有的內(nèi)容都轉(zhuǎn)換為了文本,第二是轉(zhuǎn)換之后的文本過度使用引號,這樣會給每個字符串添加多兩個字節(jié)。第三,它本身沒有schema的標(biāo)準(zhǔn)格式,比如在一個消息中序列化多個對象的時候,即使每個對象的屬性的鍵名是重復(fù)且相同的,但是轉(zhuǎn)換后的文本數(shù)據(jù)還是會重復(fù)每一個鍵名。
JSON以前的時候有一個優(yōu)勢,就是可以被Javascript引擎直接解析,但因?yàn)楝F(xiàn)在越來越重視安全性,JSON的這個優(yōu)勢也逐漸消失了,但是因?yàn)樗萖ML效率以及性能都更高,所以許多傳統(tǒng)的C/S模式都是選擇JSON,比如web服務(wù),當(dāng)有龐大的數(shù)據(jù)量以及復(fù)雜數(shù)據(jù)結(jié)構(gòu)需要從web瀏覽器中傳輸?shù)椒?wù)器的時候,JSON壓縮就起到了非常大的作用,然而中間就會存在我們剛剛說的三點(diǎn)問題,我們也不能使用傳統(tǒng)的gzip壓縮算法,因?yàn)闉g覽器不知道服務(wù)器是否支持gzip解壓。
下面我們就來看看兩種常見的JSON壓縮算法,cJSON與HPack。
cJSON壓縮算法(cJSON Compression Algorithm)
cJSON壓縮算法的特點(diǎn)就是可以使用自動類型提取壓縮JSON數(shù)據(jù)格式的內(nèi)容。它成功解決了一個非常重要的問題,就是我們上一小節(jié)提到的第三點(diǎn),將不斷重復(fù)的鍵名舍去了,我們我們來看一個例子:
使用cJSON前的數(shù)據(jù)格式:
[
{ //表示一個坐標(biāo)點(diǎn)
"x":100,
"y":100
},
{ //表示一個長方形
"x":100,
"y":100,
"width":200,
"height":150
},
{},//表示一個空對象
//以下省略數(shù)以萬計的對象
]
上面未經(jīng)壓縮的數(shù)據(jù)中,我們可以看到有非常多的空間被重復(fù)的鍵名所占據(jù),比如“x”,“y”等等,當(dāng)數(shù)據(jù)非常多的時候,這些看起來不起眼的重復(fù)鍵名會給傳輸效率帶來非常大的影響,其實(shí)解決思路也非常簡單,因?yàn)樗麄兪侵貜?fù)的,那我們??只存儲一次??不就好了?下面我們來按照我們的思路看看cJSON處理過后的數(shù)據(jù)吧。
{
"templates":[
["x","y"], //type1
["x","y","width","height"] //type2
],
"value":[
{ //第一個對象:坐標(biāo)點(diǎn)
"type":1,
"values":[
100,
100
]
},
{ //第二個對象:矩形
"type":2,
"values":[
100,
100,
200,
150
]
},
{
//第三個空對象
},
//以下省略數(shù)以萬計的對象......
]
}從上面的數(shù)據(jù)中我們可以看到,我們格式化了數(shù)據(jù),把鍵名存儲了起來,重復(fù)的就不存儲,然后值通過“type”索引來對應(yīng)鍵名,這樣在數(shù)據(jù)量龐大的時候確實(shí)減少了不少空間,但是我們仔細(xì)看“templates”內(nèi)的鍵名依舊有重復(fù)的字段存在。說明了我們還存在優(yōu)化空間,優(yōu)化完壓縮后效果如下:
{ "function": "cjson",
"templates": [
[0, "x", "y"],
[1, "width", "height"]
],
"values": [
[1, 100, 100 ], //第一個對象:坐標(biāo)點(diǎn)
[2, 100, 100, 200, 150 ], //第二個對象:矩形
[] //第三個空對象
]
} 直接看壓縮后的代碼結(jié)構(gòu)你可能不太能理解,那我們就來看看他的具體原理,為了解決“template”內(nèi)鍵名重復(fù)的字段,這個算法采用了樹這個數(shù)據(jù)結(jié)構(gòu),每遇到一個要傳輸?shù)膶ο?,就按順序把鍵值存入樹的節(jié)點(diǎn)中(灰色的節(jié)點(diǎn)是被標(biāo)記的結(jié)尾節(jié)點(diǎn)指針,表示該節(jié)點(diǎn)存儲的是某個對象最后一個屬性的鍵值),重復(fù)的就不存儲,這樣就解決了我們的問題,這個鍵值樹的變化過程如下:

最后數(shù)據(jù)在匹配鍵值的時候就根據(jù) “values” 中所標(biāo)記的結(jié)尾節(jié)點(diǎn)指針找到對應(yīng)鍵值數(shù)組,這樣就構(gòu)成了cJSON的壓縮算法。
仔細(xì)的同學(xué)就會發(fā)現(xiàn),如果一個對象中沒有"X"和"Y",只有“width”和“height”,或者鍵值節(jié)點(diǎn)順序是錯的,是不是會出問題?答案是對的,會出現(xiàn)無法匹配的鍵值的情況,所以這種方法只能在特定的場景下應(yīng)用,存在一定局限性。
總體來說,cJSON在處理非常龐大的數(shù)據(jù)量的時候效果還是非??陀^的。
JSON.HPack壓縮算法(HPack Compression Algorithm)
JSON.HPack是一種無損、跨語言、注重性能的JSON數(shù)據(jù)壓縮算法,可以讓我們在使用post請求在客戶端發(fā)送數(shù)據(jù)到服務(wù)器的過程中相對普通JSON格式節(jié)省約70%的字符。
其原理本質(zhì)上也是跟cJSON一樣將鍵值抽離開,舉個例子:
使用HPack算法前:
{
"id" : 1,
"sex" : "Female",
"age" : 38,
"classOfWorker" : "Private",
"maritalStatus" : "Married-civilian spouse present",
"education" : "1st 2nd 3rd or 4th grade",
"race" : "White"
}使用HPack算法后:
["id","sex","age","classOfWorker","mari talStatus","education","race"],
[1,"Female",38,"Private","Married-civilian spouse present","1st 2nd 3rd or 4th grade","White"]
可以看到相對于普通JSON以及cJSON少了很多字符,比如引號,各種括號等等,這種壓縮算法在數(shù)據(jù)量龐大的情況下效果也非??捎^。
HPack算法提供了幾個級別的壓縮(從0到4)。等級越高壓縮效率越高,每提升一個等級都有引入附加功能。0級壓縮通過從結(jié)構(gòu)中分離鍵值來執(zhí)行最基本的壓縮,并在索引0的元素上創(chuàng)建鍵名數(shù)組,下一個等級就可以通過假設(shè)存在重復(fù)條目來進(jìn)一步減小JSON數(shù)據(jù)的大小。
性能分析
接下來我們直接用數(shù)據(jù)來看看這幾個壓縮算法的壓縮效率,我們分別用5組大小不同的JSON文件(50KB~1MB),每個JSON文件將使用servlet容器(tomcat)提供給瀏覽器,并分別用以下算法進(jìn)行壓縮:
- Original JSON size - 未作修改的JSON數(shù)據(jù)。
- Minimized - 刪除空白和新行(最基本的js優(yōu)化)。
- Compresse cJSON - 使用CJSON壓縮算法進(jìn)行JSON壓縮。
- Compresse HPack - 使用JSON.HPack壓縮算法進(jìn)行JSON壓縮。
- Gzipped - 使用gzip和進(jìn)行JSON壓縮。
- Gzipped + Minimized - 使用gzip和刪除空白和新行(最基本的js優(yōu)化)進(jìn)行JSON壓縮。
- Gzipped + Compresse cJSON - 使用gzip和CJSON壓縮算法進(jìn)行JSON壓縮。
- Gzipped + Compresse HPack - 使用gzip和JSON.HPack壓縮算法進(jìn)行JSON壓縮。
下圖(TABLE I.RESULTES)是用以上各種方式處理完后的JSON數(shù)據(jù)大?。╞ytes),不同列表示不同的JSON數(shù)據(jù)集,不同行表示使用不同的壓縮方式。

下面第一個圖表Y軸表示JSON數(shù)據(jù)大小(bytes):

第二張圖Y軸是JSON數(shù)據(jù)大小的百分比(%),原始數(shù)據(jù)為100%:

從上面的幾個圖表中我們可以直觀地看到,單獨(dú)使用cJSON可以把原始數(shù)據(jù)大小壓縮到45%左右,單獨(dú)使用HPack可以把原始數(shù)據(jù)大小壓縮到8%左右,可見整體上HPack是優(yōu)于cJSON的。
然而我們可以看到當(dāng)使用gzip和上面提到的兩個壓縮算法相結(jié)合進(jìn)行JSON壓縮,效果才是最優(yōu)的,基本可以達(dá)到1%~2%的壓縮率。
總的來說,HPack比cJSON效率更高,速度也更快,但是在使用壓縮算法進(jìn)行傳輸?shù)倪^程中,接收的一端需要進(jìn)行相應(yīng)的解壓縮操作,否則無法使用被壓縮過后的JSON數(shù)據(jù),這一步也會存在一定的性能開銷,在我們選擇使用JSON壓縮的時候,也需要考慮到這一點(diǎn)。當(dāng)可以使用gzip進(jìn)行壓縮的時候,這種方法比其他壓縮算法的效率都高,當(dāng)兩者同時結(jié)合起來,效果顯而易見。
好了,我們這一次完整地了解了JSON序列化的發(fā)展,規(guī)范,應(yīng)用以及相關(guān)的壓縮算法,相信大家不僅對JSON壓縮算法有了更深的了解,也對JSON序列化這個技術(shù)領(lǐng)域有了深刻的認(rèn)識。
文章相關(guān)附件可以點(diǎn)擊下面的原文鏈接前往下載:
https://ost.51cto.com/resource/2290。
??想了解更多關(guān)于開源的內(nèi)容,請訪問:??






































