Performanslı Varlık Serileştirmesi: BSON ve MessagePack (JSON'a karşı)


137

Son zamanlarda Google'ın Protokol Tamponları ve JSON'a alternatif bir ikili serileştirme biçimi olan MessagePack'i de buldum .

Ayrıca MongoDB tarafından veri depolamak için kullanılan BSON serileştirme formatı da vardır .

Birisi BSON ile MessagePack arasındaki farkları ve avantajları açıklayabilir mi?


Performanslı ikili serileştirme formatlarının listesini tamamlamak için: Google'ın Protokol Tamponlarının halefi olacak Gobs da var . Bununla birlikte , dile bağlı olmayan ve Go'nun yerleşik yansımasına dayanan diğer tüm formatların aksine, en azından Go'dan başka bir dilde Gobs kütüphaneleri de vardır.


3
Çoğunlukla bir pazarlama hype yükü gibi görünüyor. ["Derlenmiş"] serileştirme biçiminin performansı kullanılan uygulamadan kaynaklanmaktadır. Bazı biçimlerin doğası gereği daha fazla yükü olmasına rağmen (örneğin, dinamik olarak işlendiği gibi JSON), biçimlerin kendilerinin "bir hızı" yoktur. Daha sonra sayfa kendini nasıl karşılaştırırsa "seç ve seç" e devam eder ... çok tarafsız bir şekilde. Benim fincan çayım değil.

6
Düzeltme: Gobs, Protokol Arabelleklerinin yerini almayı amaçlamaz ve muhtemelen hiçbir zaman yapmaz. Ayrıca, Gobs dil agnostiktir (herhangi bir dilde okunabilir / yazılabilir, bkz. Code.google.com/p/libgob ), ancak Go'nun verilerle nasıl başa çıktığıyla yakından eşleşecek şekilde tanımlanır, böylece Go ile en iyi şekilde çalışırlar.
Kyle C

6
Msgpack performans kriterlerine bağlantı kesildi ( msgpack.org/index/speedtest.png ).
Aliaksei Ramanau

Yanıtlar:


197

// MessagePack'in yazarı olduğumu lütfen unutmayın. Bu cevap taraflı olabilir.

Biçim tasarımı

  1. JSON ile uyumluluk

    İsmine rağmen, BSON'un JSON ile uyumluluğu MessagePack ile karşılaştırıldığında o kadar iyi değil.

    BSON, "ObjectId", "Min key", "UUID" veya "MD5" gibi özel tiplere sahiptir (bence bu tipler MongoDB için gereklidir). Bu türler JSON ile uyumlu değildir. Bu, nesneleri BSON'dan JSON'a dönüştürdüğünüzde, ancak elbette yalnızca bu özel türler BSON kaynağında olduğunda bazı tür bilgilerinin kaybolabileceği anlamına gelir. JSON ve BSON'u tek bir hizmette kullanmak bir dezavantaj olabilir.

    MessagePack, saydam olarak JSON'dan / JSON'a dönüştürülmek üzere tasarlanmıştır.

  2. MessagePack, BSON'dan daha küçük

    MessagePack'in biçimi BSON'dan daha az ayrıntılıdır. Sonuç olarak MessagePack, BSON'dan daha küçük nesneleri serileştirebilir.

    Örneğin, basit bir harita {"a": 1, "b": 2}, MessagePack ile 7 baytta serileştirilirken, BSON 19 bayt kullanır.

  3. BSON yerinde güncellemeyi destekler

    BSON ile, nesnenin tamamını yeniden serileştirmeden saklanan nesnenin bir kısmını değiştirebilirsiniz. Bir haritanın {"a": 1, "b": 2} içinde saklandığını ve "a" değerini 1'den 2000'e güncellemek istediğinizi varsayalım.

    MessagePack ile 1 yalnızca 1 bayt kullanır ancak 2000 3 bayt kullanır. Bu nedenle, "b" değiştirilmediği halde "b", 2 bayt geri hareket ettirilmelidir.

    BSON ile, hem 1 hem de 2000'de 5 bayt kullanılır. Bu ayrıntı nedeniyle, "b" yi hareket ettirmeniz gerekmez.

  4. MessagePack'in RPC'si var

    MessagePack, Protokol Tamponları, Tasarruf ve Avro RPC'yi destekler. Ancak BSON bunu yapmaz.

Bu farklılıklar, MessagePack'in başlangıçta ağ iletişimi için tasarlandığını, BSON ise depolar için tasarlandığını gösterir.

Uygulama ve API tasarımı

  1. MessagePack'in tür denetleme API'ları vardır (Java, C ++ ve D)

    MessagePack statik yazmayı destekler.

    JSON veya BSON ile kullanılan dinamik yazma, Ruby, Python veya JavaScript gibi dinamik diller için kullanışlıdır. Ancak statik diller için zahmetli. Sıkıcı tip kontrol kodları yazmalısınız.

    MessagePack, tür denetleme API'sı sağlar. Dinamik olarak yazılan nesneleri statik olarak yazılan nesnelere dönüştürür. İşte basit bir örnek (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>();
    }
  1. MessagePack'in IDL'si var

    Tip kontrol API'sı ile ilgilidir, MessagePack IDL'yi destekler. (teknik özelliklere şu adresten ulaşılabilir: http://wiki.msgpack.org/display/MSGPACK/Design+of+IDL )

    Protokol Tamponları ve Tasarruf, IDL gerektirir (dinamik yazmayı desteklemez) ve daha olgun IDL uygulaması sağlar.

  2. MessagePack akış API'sine sahiptir (Ruby, Python, Java, C ++, ...)

    MessagePack, akış hızlandırıcıları destekler. Bu özellik ağ iletişimi için kullanışlıdır. İşte bir örnek (Ruby):

    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
    }

33
MessagePack, veri boyutu ve sonuç olarak kablosuz performans açısından Google Protobufs ile nasıl karşılaştırılır?
Ellis

4
İlk nokta, MessagePack'in JSON'da temsil edilemeyen ham bayt özelliğine sahip olduğu gerçeğini gözler önüne seriyor. Yani bu konuda BSON ile aynı ...

4
@lttlrck Genellikle, aksi belirtilmedikçe ve kanalın her iki tarafında kabul edilmedikçe ham baytların bir dize (genellikle utf-8) olduğu varsayılır. msgpack bir akış / serileştirme biçimi olarak kullanılır ... ve daha az insan tarafından okunabilir olsa da json daha az ayrıntılı.
Tracker1

4
"MessagePack'in tür denetleme API'leri var. BSON yok." Tamamen doğru değil. Bu aslında statik olarak yazılan dillerde BSON uygulamaları için de geçerlidir.
Brandon Black

1
MessagePack artık bir BINARY veri türüne sahip olduğundan, JSON ile 1-1 serileştirme uyumluluğu argümanı artık tamamen doğru değil.
zimbatm

16

Bu sorunun bu noktada biraz tarihli olduğunu biliyorum ... Bence istemci / sunucu ortamınızın nasıl göründüğüne bağlı olduğunu belirtmek çok önemli.

Baytları denetlemeden, ileti kuyruk sistemi veya akış günlük girişleri gibi diske birden çok kez geçiriyorsanız, kompakt boyutu vurgulamak için ikili kodlamayı tercih edebilirsiniz. Aksi takdirde, farklı ortamlarda durumdan duruma göre bir sorundur.

Bazı ortamlar msgpack / protobuf'lara çok hızlı serileştirme ve serileştirme yapabilir, diğerleri çok fazla değil. Genel olarak, dil / ortam ne kadar düşük düzeyde olursa, ikili serileştirme o kadar iyi çalışır. Daha üst düzey dillerde (node.js, .Net, JVM) genellikle JSON serileştirmesinin gerçekten daha hızlı olduğunu görürsünüz. O zaman soru şu olur: Ağınız bellek / CPU'nuzdan daha fazla mı yoksa daha az mı kısıtlanıyor?

Msgpack vs bson vs protokol arabellekleri ile ilgili olarak ... msgpack grubun en az baytıdır, protokol arabellekleri yaklaşık aynıdır. BSON, diğer ikisinden daha geniş yerel türleri tanımlar ve nesne modunuzla daha iyi eşleşebilir, ancak bu onu daha ayrıntılı hale getirir. Protokol arabellekleri, ikili aktarım / depolama formatı için daha doğal bir format haline getirecek şekilde akış için tasarlanma avantajına sahiptir.

Kişisel olarak, daha hafif trafiğe açık bir ihtiyaç olmadıkça, JSON'un doğrudan sunduğu şeffaflığa yönelirim. Gzip veri içeren HTTP üzerinden, ağ ek yükündeki fark, formatlar arasında daha az sorun yaratır.


6
Yerel MsgPack yalnızca anahtar uzunluğu (her zaman mevcut metin olan) "a" veya "b" gibi kısa olduğu veya aksi takdirde tüm yükün önemsiz bir parçası olduğu için boyut olarak ProtocolBuffers ile etkilidir . Alan tanımlayıcılarını id'lerle eşlemek için bir IDL / derleme kullanan ProtocolBuffers'ta her zaman kısadırlar. Bu aynı zamanda ProtocolBuffers kesinlikle değil MsgPack "dinamik" kılan şeydir ..
user2864740

2
Gzip / havasını alın: bitiş noktası iyi olsa gerçekten iyi böyle anahtarlar "uzun ama çok tekrarlanan" durumlarda tuşların fazlalığını kullanımı vardır (MsgPack JSON / BSON ve XML vb üzerinde birçok kayıtları) ama yardım olmaz ProtocolBuffers burada .. Avro, şemayı ayrı ayrı ileterek anahtar fazlalık ortadan kaldırmayı manuel olarak yapar.
user2864740

4

Hızlı test, küçültülmüş JSON'un ikili MessagePack'ten daha hızlı serileştirildiğini gösterir. Testlerde Article.json, 550kb küçültülmüş JSON, Article.mpack 420kb MP-sürümüdür. Elbette bir uygulama sorunu olabilir.

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);
}

Yani zamanlar:

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

Böylece yer kazanılıyor, ama daha hızlı mı? Hayır.

Test edilmiş sürümler:

Anarki:Downloads oleksii$ node --version
v0.8.12
Anarki:Downloads oleksii$ npm list msgpack
/Users/oleksii
└── msgpack@0.1.7  

7
Kesinlikle uygulamalara bağlıdır. Python 2.7.3 ile bir 489K test.json (409K eşdeğer test.msgpack) paketini açtığım testlerim, 10.000 yineleme için 2.6.2'nin simplejson66.7 saniye ve 0.2.2'nin msgpacksadece 28.8 olduğunu gösteriyor.
Gün

2
Bu Article.json nereden geldi?
Ant6n

millet, test kodu yukarıdaki yorumumda, başka ne bekliyordunuz, Article.json projemizden json serileştirilmiş bir nesnedir. Ve şimdiye kadar bu sonuçlar alakasız olabilir
Oleksiy Khilkevich

14
JS, JSON yerel olarak C ++ 'da uygulanırken JSG, JS'de msgpack uyguladığından bu adil bir performans karşılaştırması değildir.
Alex Panchenko

2
MessagePack'i Latince Romalılardan daha iyi konuşturmaya çalışıyorsunuz. JSON, JavaScript'te MessagePack yazılırken yorumlanan yerel (C ++) JavaScript'tir. Bu temelde biri JavaScript ile yazılmış diğeri C ++ ile yazılmış iki kod parçacığını karşılaştırmaktadır.
Ramazan Polat

0

Henüz bahsedilmeyen önemli bir fark BSON'un tüm belge ve daha fazla iç içe alt belge için bayt cinsinden boyut bilgisi içermesidir.

document    ::=     int32 e_list

Bunun, boyut ve performansın önemli olduğu kısıtlı ortamlar (örneğin gömülü) için iki önemli faydası vardır.

  1. Ayrıştıracağınız verilerin tam bir belgeyi temsil edip etmediğini veya bir noktada daha fazla bilgi istemeniz gerekip gerekmediğini hemen kontrol edebilirsiniz (bazı bağlantı veya depolamadan olsun). Bu büyük olasılıkla eşzamansız bir işlem olduğundan, ayrıştırmadan önce yeni bir istek gönderebilirsiniz.
  2. Verileriniz, sizin için alakasız bilgiler içeren tüm alt belgeleri içerebilir. BSON, atlamak için alt belgenin boyut bilgilerini kullanarak alt belgenin ötesindeki bir sonraki nesneye kolayca geçmenizi sağlar. Diğer yandan msgpack, içinde harita adı verilen öğelerin sayısını içerir (BSON'un alt belgelerine benzer). Bu hiç şüphesiz yararlı bilgiler olsa da ayrıştırıcıya yardımcı olmaz. Hala haritanın içindeki her nesneyi ayrıştırmanız gerekir ve bunu atlayamazsınız. Verilerinizin yapısına bağlı olarak, bunun performans üzerinde büyük bir etkisi olabilir.

0

MessagePack vs BSON'un kodlama ve kod çözme hızını karşılaştırmak için hızlı bir karşılaştırma yaptım. BSON en azından büyük ikili dizileriniz varsa daha hızlıdır:

BSON writer: 2296 ms (243487 bytes)
BSON reader: 435 ms
MESSAGEPACK writer: 5472 ms (243510 bytes)
MESSAGEPACK reader: 1364 ms

Neuecc tarafından C # Newtonsoft.Json ve MessagePack kullanma:

    public class TestData
    {
        public byte[] buffer;
        public bool foobar;
        public int x, y, w, h;
    }

    static void Main(string[] args)
    {
        try
        {
            int loop = 10000;

            var buffer = new TestData();
            TestData data2;
            byte[] data = null;
            int val = 0, val2 = 0, val3 = 0;

            buffer.buffer = new byte[243432];

            var sw = new Stopwatch();

            sw.Start();
            for (int i = 0; i < loop; i++)
            {
                data = SerializeBson(buffer);
                val2 = data.Length;
            }

            var rc1 = sw.ElapsedMilliseconds;

            sw.Restart();
            for (int i = 0; i < loop; i++)
            {
                data2 = DeserializeBson(data);
                val += data2.buffer[0];
            }
            var rc2 = sw.ElapsedMilliseconds;

            sw.Restart();
            for (int i = 0; i < loop; i++)
            {
                data = SerializeMP(buffer);
                val3 = data.Length;
                val += data[0];
            }

            var rc3 = sw.ElapsedMilliseconds;

            sw.Restart();
            for (int i = 0; i < loop; i++)
            {
                data2 = DeserializeMP(data);
                val += data2.buffer[0];
            }
            var rc4 = sw.ElapsedMilliseconds;

            Console.WriteLine("Results:", val);
            Console.WriteLine("BSON writer: {0} ms ({1} bytes)", rc1, val2);
            Console.WriteLine("BSON reader: {0} ms", rc2);
            Console.WriteLine("MESSAGEPACK writer: {0} ms ({1} bytes)", rc3, val3);
            Console.WriteLine("MESSAGEPACK reader: {0} ms", rc4);
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }

        Console.ReadLine();
    }

    static private byte[] SerializeBson(TestData data)
    {
        var ms = new MemoryStream();

        using (var writer = new Newtonsoft.Json.Bson.BsonWriter(ms))
        {
            var s = new Newtonsoft.Json.JsonSerializer();
            s.Serialize(writer, data);
            return ms.ToArray();
        }
    }

    static private TestData DeserializeBson(byte[] data)
    {
        var ms = new MemoryStream(data);

        using (var reader = new Newtonsoft.Json.Bson.BsonReader(ms))
        {
            var s = new Newtonsoft.Json.JsonSerializer();
            return s.Deserialize<TestData>(reader);
        }
    }

    static private byte[] SerializeMP(TestData data)
    {
        return MessagePackSerializer.Typeless.Serialize(data);
    }

    static private TestData DeserializeMP(byte[] data)
    {
        return (TestData)MessagePackSerializer.Typeless.Deserialize(data);
    }

0

Yazarın dediği gibi , MessagePack başlangıçta ağ iletişimi için tasarlanmıştır, BSON ise depolar için tasarlanmıştır.

MessagePack kompakttır, BSON ise ayrıntılıdır. MessagePack alandan tasarruf sağlarken BSON CURD (zaman açısından verimli) için tasarlanmıştır.

En önemlisi, MessagePack'in tip sistemi (önek) Huffman kodlamasını takip ediyor, burada bir Huffman MessagePack ağacı çizdim (resmi görmek için bağlantıya tıklayın) :

Huffman Tree of MessagePack

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.