效率:測試
msgpack,json,serialize
打包10000次
長度50,62,87
耗時9,95ms,17.45ms,8.85ms
解包
耗時14.76ms,23.93ms,14.61ms
MessagePack 是個什么東東?先來看一段官方的解釋:
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.
MessagePack 是一個高效的二進制序列化格式。它讓你像JSON一樣可以在各種語言之間交換數據。但是它比JSON更快、更小。小的整數會被編碼成一個字節,短的字符串僅僅只需要比它的長度多一字節的大小。
官方用一句話總結了這個東東:
It’s like JSON.
but fast and small.
最初研究MessagePack 大概是兩年前了,還開了個講座給大家講MessagePack是個什么東西,大概用在什么場合,它是不是給Javascript用的之類的。但是兩年過去了,由於博客平台老系統太多,以至於這個協議一直沒有能推進使用。后來,redis宣布支持MessagePack格式,以及pintrest等公司,也在積極得使用這個協議進行開發,說明這個格式確實有很多先進性。
這張圖片是以前MessagePack 官方網站的首頁圖片,數字對比確實很能反映問題,筆者不是很了解protocol buffers,XML又太老土了,就跳過他們倆了,只討論JSON和MessagePack了。
為啥會小?
先大概說下MessagePack 為啥會比JSON小吧,先來段json:
{“name“:”heyue“,”sex“:”\u7537“,”company“:”sina“,”age“:30}
這個json長度為57字節,但是為了表示這個數據結構(所有標紅色的地方就是他為了表示這個數據結構而不得不添加的),它用了23個字節(就是那些大括號、引號、冒號之類的,他們是白白多出來的)。大家可以去http://json.org/ 上看看json的數據標示定義。
換成MessagePack,我只能給大家貼代碼和結果了,38字節:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<?php
$arr
=
array
(
'name'
=>
"heyue"
,
'sex'
=>
'男'
,
'company'
=>
'sina'
,
'age'
=>30);
echo
"Json:"
.
strlen
(json_encode(
$arr
)).
"\n"
;
echo
"Messagepack:"
.
strlen
(msgpack_pack(
$arr
)).
"\n"
;
$str
=
"何躍新浪"
;
echo
json_encode(
$str
).
"\n"
;
echo
'json_str:'
.
strlen
(json_encode(
$str
)).
"\n"
;
echo
'MessagePack_str:'
.
strlen
(msgpack_pack(
$str
)).
"\n"
;
$str
=
"sina china"
;
echo
json_encode(
$str
).
"\n"
;
echo
'json_str:'
.
strlen
(json_encode(
$str
)).
"\n"
;
echo
'MessagePack_str:'
.
strlen
(msgpack_pack(
$str
)).
"\n"
;
?>
Json:57
Messagepack:38
//從這里可以看出MessagePack比json少了好多
"\u4f55\u8dc3\u65b0\u6d6a"
json_str:26
MessagePack_str:13
//在UTF-8多字節字符中,MessagePack采用原生態存儲,4個漢字,只用了13字節,比原始的只多了1字節
"sina china"
json_str:12
MessagePack_str:11
//英文字符呢?這個僅僅是比json少了一個引號的大小。
|
我不能給大家算比例,因為這個得看MessagePack的壓縮算法,MessagePack的核心壓縮方式:
1.true、false 之類的:這些太簡單了,直接給1個字節,(0xc2 表示true,0xc3表示false)
2.不用表示長度的:就是數字之類的,他們天然是定長的,是用一個字節表示后面的內容是什么東東,比如用(0xcc 表示這后面,是個uint 8,用oxcd表示后面是個uint 16,用 0xca 表示后面的是個float 32).
3.不定長的:比如字符串、數組,類型后面加 1~4個字節,用來存字符串的長度,如果是字符串長度是256以內的,只需要1個字節,MessagePack能存的最長的字符串,是(2^32 -1 ) 最長的4G的字符串大小。
4.ext結構:表示特定的小單元數據。
5.高級結構:MAP結構,就是key=>val 結構的數據,和數組差不多,加1~4個字節表示后面有多少個項。
這個是官方的數據表示結構文檔:https://gist.github.com/frsyuki/5432559
總的來說,MessagePack對數字、多字節字符、數組等都做了很多優化,減少了無用的字符,二進制格式,也保證不用字符化帶來額外的存儲空間的增加,所以MessagePack比JSON小是肯定的,小多少,得看你的數據。如果你用來存英文字符串,那幾乎是沒有區別….
為啥會快?
先說說JSON怎么解析吧,我們開發中一般都用cJSON這個庫,cJSON存儲的時候是采用鏈表存儲的,其訪問方式很像一顆樹。每一個節點可以有兄妹節點,通過next/prev指針來查找,它類似雙向鏈表;每個節點也可以有孩子節點,通過child指針來訪問,進入下一層。問題就是首先,構造這個鏈表的時候,得一個字符一個字符地匹配過去吧,得判斷是不是引號、括號之類的吧…
但是MessagePack 則簡單多了,直接一遍遍歷過去了,從前面的數據頭,就可以知道后面的是什么數據,指針應該向后移動多少,比JSON的構建鏈表少了很多比較的過程。
來計算個數據吧,把剛才的數組,encode、decode重復1000萬次:
msgpack_unpack(msgpack_pack($arr));
json_decode(json_encode($arr));
Json:37.099s
MessagePack:22.050s
大概是快這么多吧,如果數組更大,理論上,MessagePack比Json快更多。
MessagePack的常用的地方:
MessagePack 不是給JS用的,雖然它有JS的庫,但是用瀏覽器來解析MessagePack是一件很悲劇的事情,我曾經測試過(如果我還能找到,我會提供代碼),在低端瀏覽器下,JS計算MessagePack會卡死在那里,畢竟JSON是javascript親生的,用起來自然比MessagePack要容易。
MessagePack主要用於結構化數據的緩存和存儲:
1.存在Memcache中,因為它比json小,可以省下一些內存來,速度也比json快一些,頁面速度自然快一個檔次。當然,也有一種情況,我在mc中存json,然后直接出來就是頁面可用的json,都不用解析json了(當然這個在實際開發中比較少見)。
2.存在可以持久化的Key-val存儲中。
MessagePack的現狀:
我就說PHP吧,因為C、C++的沒啥好說的,就是解包、打包,速度比JSON快一些,但是業務邏輯的數據太多,還是先考慮上層的吧。
PHP的MessagePack的擴展的安裝:
1
2
3
4
5
6
|
可以用PECL的安裝方式:
pecl
install
msgpack
也可以編譯源碼安裝:
$
/path/to/phpize
$.
/configure
$
make
&&
make
install
|
使用方法:
1
2
3
4
5
|
<?php
$data
=
array
(0=>1,1=>2,2=>3);
$msg
= msgpack_pack(
$data
);
$data
= msgpack_unpack(
$msg
);
?>
|
這個MessagePack的PHP擴展,是傳說中的鳥哥Laruence開發維護的,在鳥哥的Yar中,也使用了MessagePack 作為打包協議之一。
從現狀看來,MessagePack目前還很少有公司大規模使用?這是為什么呢?由於沒有讀過MessagePack的相關的源碼,所以在這個范疇,鳥哥最有發言權…
后來,redis 2.6支持了MessagePack…
先寫到這里了,有空了,再補充一些,比如MessagePack 和 protocol buffer的異同之類的,洗洗睡了…