2011-06-15 125 views
113

最近我發現MessagePack,替代二進制序列化格式,以谷歌的Protocol BuffersJSON也優於兩者。高性能系列化實體:BSON VS MessagePack(VS JSON)

此外還有MongoDB用於存儲數據的BSON序列化格式。

有人可以詳細說明區別以及BSON與MessagePack的區別/優點


剛剛完成的高性能的二進制序列化格式列表:也有Gobs 這將是谷歌的協議緩衝 的繼任者。然而, 與所有其他提及的格式不同,它們不是語言不可知的,並且依賴於 Go's built-in reflection ,至少在Go以外的語言中也有Gobs庫。

+3

似乎主要是像市場炒作負荷。 [「編譯」]序列化格式的性能是由於使用的實現。儘管某些格式本身具有更多開銷(例如JSON,因爲它全部是動態處理的),但格式本身並不「有速度」。然後頁面繼續「挑選」它如何比較自己......這是一種非公正的時尚。不是我喜歡的。 – 2011-06-15 09:20:53

+6

更正:Gobs無意取代Protocol Buffers,也可能永遠不會。此外,Gobs是語言不可知的(它們可以用任何語言閱讀/編寫,請參閱http://code.google.com/p/libgob/),但它們被定義爲與Go處理數據的方式非常匹配,因此它們可以工作與Go最好。 – 2011-06-15 18:59:23

+5

鏈接到msgpack性能基準測試失敗(http://msgpack.org/index/speedtest.png)。 – 2012-10-04 21:12:23

回答

157

//請注意我是MessagePack的作者。這個答案可能是有偏見的。

格式設計

  1. 與JSON

    儘管它的名字的兼容性,與MessagePack相比BSON與JSON的兼容性也不是那麼好。

    BSON有「ObjectId」,「Min key」,「UUID」或「MD5」(我認爲MongoDB需要這些類型)的特殊類型。這些類型與JSON不兼容。這意味着某些類型信息在將對象從BSON轉換爲JSON時會丟失。在單一服務中使用JSON和BSON可能是不利的。

    MessagePack被設計爲從/到JSON透明轉換。

  2. MessagePack比BSON

    小MessagePack的格式比BSON更簡潔。結果,MessagePack可以序列化小於BSON的對象。

    例如,一個簡單的映射{「a」:1,「b」:2}被7個字節的MessagePack序列化,而BSON使用19個字節。

  3. BSON支持就地更新

    隨着BSON,您可以修改存儲對象的一部分,而無需重新整序列化對象。假設地圖{「a」:1,「b」:2}存儲在一個文件中,並且您希望將「a」的值從1更新爲2000.

    使用MessagePack,1僅使用1個字節但2000年使用3個字節。所以「b」必須向後移動2個字節,而「b」沒有被修改。

    使用BSON,1和2000都使用5個字節。由於這種冗長,你不必移動「b」。

  4. MessagePack具有RPC

    MessagePack,協議緩衝區,節儉和Avro的支持RPC。但是BSON沒有。

這些差異意味着MessagePack最初設計用於網絡通信,而BSON設計用於存儲。

實施和API設計

  1. MessagePack具有類型檢查的API(JAVA,C++和d)

    MessagePack支持靜態打字。

    用於JSON或BSON的動態類型對於Ruby,Python或JavaScript等動態語言非常有用。但是對於靜態語言來說很麻煩。你必須寫無聊的類型檢查代碼。

    MessagePack提供了類型檢查API。它將動態類型的對象轉換爲靜態類型的對象。下面是一個簡單的例子(C++):

    #include <msgpack.hpp> 
    
    class myclass { 
    private: 
        std::string str; 
        std::vector<int> vec; 
    public: 
        // This macro enables this class to be serialized/deserialized 
        MSGPACK_DEFINE(str, vec); 
    }; 
    
    int main(void) { 
        // serialize 
        myclass m1 = ...; 
    
        msgpack::sbuffer buffer; 
        msgpack::pack(&buffer, m1); 
    
        // deserialize 
        msgpack::unpacked result; 
        msgpack::unpack(&result, buffer.data(), buffer.size()); 
    
        // you get dynamically-typed object 
        msgpack::object obj = result.get(); 
    
        // convert it to statically-typed object 
        myclass m2 = obj.as<myclass>(); 
    } 
    
  2. MessagePack具有IDL

    它相關的類型檢查API,MessagePack支持IDL。 (規範可從:http://wiki.msgpack.org/display/MSGPACK/Design+of+IDL

    Protocol Buffers和Thrift需要IDL(不支持動態輸入)並提供更成熟的IDL實現。

  3. MessagePack已經流API(紅寶石,Python和Java和C++,...)

    MessagePack支持流解串器。該功能對網絡通信非常有用。下面是一個例子(紅寶石):

    require 'msgpack' 
    
    # write objects to stdout 
    $stdout.write [1,2,3].to_msgpack 
    $stdout.write [1,2,3].to_msgpack 
    
    # read objects from stdin using streaming deserializer 
    unpacker = MessagePack::Unpacker.new($stdin) 
    # use iterator 
    unpacker.each {|obj| 
        p obj 
    } 
    
+25

MessagePack與Google Protobufs在數據大小方面以及空中性能方面的比較如何? – Ellis 2011-06-17 11:15:13

+2

第一點掩蓋了MessagePack具有無法用JSON表示的原始字節能力的事實。所以它只是同BSON在這方面... – hplbsh 2011-09-02 02:40:33

+3

@lttlrck一般來說,原始字節被認爲是一個字符串(通常是UTF-8),除非另有預期,並同意在通道的兩側。 msgpack被用作流/序列化格式...並且較少詳細說明json ..雖然也較少用於人類可讀。 – Tracker1 2012-08-08 22:16:28

4

快速測試顯示縮小的JSON反序列化不是二進制MessagePack更快。在測試中,Article.json是550kb縮小的JSON,Article.mpack是它的420kb MP版本。當然可能是一個實現問題。

MessagePack:

//test_mp.js 
var msg = require('msgpack'); 
var fs = require('fs'); 

var article = fs.readFileSync('Article.mpack'); 

for (var i = 0; i < 10000; i++) { 
    msg.unpack(article);  
} 

JSON:

// test_json.js 
var msg = require('msgpack'); 
var fs = require('fs'); 

var article = fs.readFileSync('Article.json', 'utf-8'); 

for (var i = 0; i < 10000; i++) { 
    JSON.parse(article); 
} 

所以時間是:

Anarki:Downloads oleksii$ time node test_mp.js 

real 2m45.042s 
user 2m44.662s 
sys  0m2.034s 

Anarki:Downloads oleksii$ time node test_json.js 

real 2m15.497s 
user 2m15.458s 
sys  0m0.824s 

因此節省空間,但速度更快?

測試版本:

Anarki:Downloads oleksii$ node --version 
v0.8.12 
Anarki:Downloads oleksii$ npm list msgpack 
/Users/oleksii 
└── [email protected] 
+5

絕對取決於實現。我使用Python 2.7.3對489K test.json(相當於409K test.msgpack)進行了測試,結果表明,對於10,000次迭代,「simplejson」2.6.2需要66.7秒,「msgpack」0.2.2只需要28.8。 – Day 2012-11-06 23:15:13

+0

[測試代碼](http://pastebin.com/ZkS0kLB2)(pastebin) – Day 2012-11-06 23:21:05

+0

@Oleksiy請提供測試代碼。 – 2012-12-07 20:41:34

13

我知道這個問題是在這一點上有點過時...我想提一提,它取決於你的客戶機/服務器環境是什麼樣子是非常重要的。

如果要傳遞的字節多次未經檢驗,例如用一個消息隊列系統或流式傳輸的日誌條目到磁盤上,則很可能更喜歡的二進制編碼來強調緊湊的尺寸。否則,這是一個在不同環境下的案例。

某些環境會有非常快速的序列化和反序列化到/從msgpack/protobuf的年代,別人沒有這麼多。一般來說,語言/環境越低級,更好的二進制序列化就可以工作。在更高級別的語言(node.js,.Net,JVM)中,您經常會看到JSON序列化實際上更快。那麼問題就是你的網絡開銷比你的內存/ CPU多少受到限制?

至於msgpack VS BSON VS協議緩衝區... msgpack是該組的至少字節,協議緩衝區是大約相同的。 BSON定義了比其他兩種更廣泛的本機類型,並且可能與對象模式更匹配,但這使得它更加冗長。協議緩衝區具有被設計爲流式傳輸的優勢...這使得它成爲二進制傳輸/存儲格式更自然的格式。

我個人的偏向透明度JSON提供直接,除非有較輕的交通顯然需要。通過使用壓縮數據的HTTP,網絡開銷的差異更不是格式之間的問題。

+5

本機MsgPack *只有*效率與ProtocolBuffers尺寸明智的密鑰長度(這是始終存在的文本)是*短*如「a」或「b」 - *或否則是無意義的部分整個有效載荷*。在ProtocolBuffers中它們總是很短,它使用IDL /編譯將字段描述符映射到ID。這也是什麼使MsgPack「動態」,其中ProtocolBuffers是肯定不是.. – user2864740 2015-02-26 22:26:44

+0

終點是好的,雖然:gzip/deflate是*真的很好*處理密鑰冗餘的情況下,如果這些密鑰是「更長,但重複很多「(MsgPack,JSON/BSON和XML等等* *許多*記錄),但在這裏完全無助於ProtocolBuffers。Avro通過單獨傳輸模式手動完成關鍵冗餘消除操作。 – user2864740 2015-02-26 22:27:25