Serialización de entidad de rendimiento: BSON vs MessagePack (vs JSON)

137

Recientemente encontré MessagePack , un formato de serialización binario alternativo a los Protocol Buffers de Google y JSON que también supera a ambos.

También está el formato de serialización BSON que utiliza MongoDB para almacenar datos.

¿Alguien puede elaborar las diferencias y las desventajas de BSON vs MessagePack ?


Solo para completar la lista de formatos de serialización binaria performantes: también hay Gobs que serán los sucesores de los Buffers de protocolo de Google . Sin embargo, en contraste con todos los otros formatos mencionados, estos no son independientes del lenguaje y dependen de la reflexión incorporada de Go, también hay bibliotecas de Gobs para al menos otro idioma que no sea Go.

Alex
fuente
3
Parece sobre todo como una carga de publicidad publicitaria. El rendimiento de un formato de serialización ["compilado"] se debe a la implementación utilizada. Si bien algunos formatos tienen una sobrecarga inherentemente mayor (por ejemplo, JSON, ya que todo se procesa dinámicamente), los formatos en sí mismos no "tienen velocidad". La página continúa para "elegir y elegir" cómo se compara a sí misma ... es una moda muy imparcial. No es mi taza de té.
66
Corrección: los Gobs no están destinados a reemplazar Protocol Buffers, y probablemente nunca lo harán. Además, los Gobs son independientes del idioma (se pueden leer / escribir en cualquier idioma, consulte code.google.com/p/libgob ), pero están definidos para que coincidan estrechamente con la forma en que Go maneja los datos, por lo que funcionan mejor con Go.
Kyle C
66
El enlace a los puntos de referencia de rendimiento de msgpack está roto ( msgpack.org/index/speedtest.png ).
Aliaksei Ramanau

Respuestas:

197

// Tenga en cuenta que soy autor de MessagePack. Esta respuesta puede ser parcial.

Diseño de formatos

  1. Compatibilidad con JSON

    A pesar de su nombre, la compatibilidad de BSON con JSON no es tan buena en comparación con MessagePack.

    BSON tiene tipos especiales como "ObjectId", "Min key", "UUID" o "MD5" (creo que MongoDB requiere estos tipos). Estos tipos no son compatibles con JSON. Eso significa que parte de la información de tipo puede perderse cuando convierte objetos de BSON a JSON, pero por supuesto solo cuando estos tipos especiales están en la fuente BSON. Puede ser una desventaja usar JSON y BSON en un solo servicio.

    MessagePack está diseñado para convertirse de forma transparente de / a JSON.

  2. MessagePack es más pequeño que BSON

    El formato de MessagePack es menos detallado que BSON. Como resultado, MessagePack puede serializar objetos más pequeños que BSON.

    Por ejemplo, un mapa simple {"a": 1, "b": 2} se serializa en 7 bytes con MessagePack, mientras que BSON usa 19 bytes.

  3. BSON admite la actualización en el lugar

    Con BSON, puede modificar parte del objeto almacenado sin volver a serializar todo el objeto. Supongamos que un mapa {"a": 1, "b": 2} se almacena en un archivo y desea actualizar el valor de "a" de 1 a 2000.

    Con MessagePack, 1 usa solo 1 byte pero 2000 usa 3 bytes. Por lo tanto, "b" debe moverse hacia atrás en 2 bytes, mientras que "b" no se modifica.

    Con BSON, tanto 1 como 2000 usan 5 bytes. Debido a esta verbosidad, no tienes que mover "b".

  4. MessagePack tiene RPC

    MessagePack, Protocol Buffers, Thrift y Avro admiten RPC. Pero BSON no lo hace.

Estas diferencias implican que MessagePack está diseñado originalmente para la comunicación de red, mientras que BSON está diseñado para almacenamientos.

Implementación y diseño de API

  1. MessagePack tiene API de verificación de tipos (Java, C ++ y D)

    MessagePack admite la escritura estática.

    La escritura dinámica utilizada con JSON o BSON es útil para lenguajes dinámicos como Ruby, Python o JavaScript. Pero problemático para los lenguajes estáticos. Debe escribir códigos de verificación de tipo aburridos.

    MessagePack proporciona API de verificación de tipo. Convierte objetos de tipo dinámico en objetos de tipo estático. Aquí hay un ejemplo simple (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 tiene IDL

    Está relacionado con la API de verificación de tipos, MessagePack admite IDL. (la especificación está disponible en: http://wiki.msgpack.org/display/MSGPACK/Design+of+IDL )

    Protocol Buffers y Thrift requieren IDL (no soporta tipado dinámico) y proporcionan una implementación IDL más madura.

  2. MessagePack tiene API de transmisión (Ruby, Python, Java, C ++, ...)

    MessagePack admite deserializadores de transmisión. Esta característica es útil para la comunicación en red. Aquí hay un ejemplo (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
    }
Sadayuki Furuhashi
fuente
33
¿Cómo se compara MessagePack con Google Protobufs en términos de tamaño de datos y, en consecuencia, de rendimiento en el aire?
Ellis
44
El primer punto pasa por alto el hecho de que MessagePack tiene una capacidad de bytes sin procesar que no se puede representar en JSON. Así que es lo mismo que BSON en ese sentido ...
44
@lttlrck Generalmente, se supone que los bytes sin procesar son una cadena (generalmente utf-8), a menos que se espere lo contrario y se acuerde en ambos lados del canal. msgpack se usa como un formato de secuencia / serialización ... y menos detallado que json ... aunque también menos legible para los humanos.
Rastreador1
44
"MessagePack tiene API de verificación de tipos. BSON no". No del todo exacto. Esto también es cierto para las implementaciones de BSON en lenguajes de tipo estático también.
Brandon Black
1
MessagePack ahora tiene un tipo de datos BINARY, por lo que el argumento de la compatibilidad de deserialización 1-1 con JSON ya no es del todo cierto.
zimbatm
16

Sé que esta pregunta está un poco anticuada en este momento ... Creo que es muy importante mencionar que depende de cómo se vea su entorno cliente / servidor.

Si está pasando bytes varias veces sin inspección, como con un sistema de cola de mensajes o entradas de registro de transmisión al disco, entonces puede preferir una codificación binaria para enfatizar el tamaño compacto. De lo contrario, es un problema caso por caso con diferentes entornos.

Algunos entornos pueden tener una serialización y deserialización muy rápida hacia / desde msgpack / protobuf's, otros no tanto. En general, cuanto más bajo sea el lenguaje / entorno, mejor funcionará la serialización binaria. En los lenguajes de nivel superior (node.js, .Net, JVM), a menudo verá que la serialización JSON es realmente más rápida. Entonces, la pregunta es si su sobrecarga de red es más o menos limitada que su memoria / CPU.

Con respecto a los búferes msgpack vs bson vs protocolo ... msgpack es el mínimo de bytes del grupo, los búferes de protocolo son casi iguales. BSON define tipos nativos más amplios que los otros dos, y puede ser una mejor coincidencia con su modo de objeto, pero esto lo hace más detallado. Los buffers de protocolo tienen la ventaja de estar diseñados para transmitir ... lo que lo convierte en un formato más natural para un formato de transferencia / almacenamiento binario.

Personalmente, me inclinaría hacia la transparencia que JSON ofrece directamente, a menos que haya una clara necesidad de un tráfico más ligero. Sobre HTTP con datos comprimidos, la diferencia en la sobrecarga de la red es un problema aún menor entre los formatos.

Rastreador1
fuente
66
Native MsgPack solo es eficiente con ProtocolBuffers en cuanto al tamaño, ya que la longitud de las claves (que siempre están presentes) son cortas , como "a" o "b", o son una parte insignificante de toda la carga útil . Siempre son cortos en ProtocolBuffers, que utiliza un IDL / compilación para asignar descriptores de campo a identificadores. Esto es también lo que hace MsgPack "dinámica", que ProtocolBuffers es sin duda no es ..
user2864740
2
Sin embargo, el punto final es bueno: gzip / deflate son realmente buenos ya que manejan la redundancia de claves en casos donde tales claves son "más largas pero se repiten mucho" (MsgPack, JSON / BSON y XML, etc. en muchos registros) pero no ayudarán ProtocolBuffers en absoluto aquí .. Avro elimina manualmente la redundancia de claves transmitiendo el esquema por separado.
user2864740
4

La prueba rápida muestra que JSON minimizado se deserializa más rápido que MessagePack binario. En las pruebas, Article.json es un JSON minimizado de 550 kb, Article.mpack es una versión MP de 420 kb. Puede ser un problema de implementación, por supuesto.

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

Entonces los tiempos son:

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

¿Entonces se ahorra espacio, pero más rápido? No.

Versiones probadas:

Anarki:Downloads oleksii$ node --version
v0.8.12
Anarki:Downloads oleksii$ npm list msgpack
/Users/oleksii
└── [email protected]  
Oleksiy Khilkevich
fuente
77
Definitivamente depende de las implementaciones. Mis pruebas con Python 2.7.3 desempaquetando 489K test.json (409K equivalente test.msgpack) muestran que para 10,000 iteraciones simplejson2.6.2 toma 66.7 segundos y msgpack0.2.2 toma solo 28.8.
Día
2
¿De dónde vino este Article.json?
Antón
amigos, el código de prueba está en mi comentario anterior, qué más esperaban, Article.json es un objeto serializado json de nuestro proyecto. Y a estas alturas esos resultados pueden ser irrelevantes de todos modos
Oleksiy Khilkevich
14
Esta no es una comparación de rendimiento justa, ya que JS ha implementado JSON de forma nativa en C ++, mientras que msgpack en JS.
Alex Panchenko
2
Estás tratando de hacer que MessagePack hable latín mejor que los romanos. JSON es nativo (C ++) a JavaScript, mientras que MessagePack está escrito en JavaScript, que se interpreta. Básicamente, esto compara dos fragmentos de código, uno escrito en JavaScript y otro escrito en C ++.
Ramazan Polat
0

Una diferencia clave aún no mencionada es que BSON contiene información de tamaño en bytes para todo el documento y otros subdocumentos anidados.

document    ::=     int32 e_list

Esto tiene dos beneficios principales para entornos restringidos (por ejemplo, integrados) donde el tamaño y el rendimiento son importantes.

  1. Puede verificar de inmediato si los datos que va a analizar representan un documento completo o si necesitará solicitar más en algún momento (ya sea desde alguna conexión o almacenamiento). Como es muy probable que sea una operación asincrónica, es posible que ya envíe una nueva solicitud antes de analizar.
  2. Sus datos pueden contener subdocumentos completos con información irrelevante para usted. BSON le permite desplazarse fácilmente al siguiente objeto más allá del subdocumento utilizando la información de tamaño del subdocumento para omitirlo. msgpack, por otro lado, contiene la cantidad de elementos dentro de lo que se llama un mapa (similar a los subdocumentos de BSON). Si bien esta es, sin duda, información útil, no ayuda al analizador. Aún tendría que analizar cada objeto dentro del mapa y no puede simplemente omitirlo. Dependiendo de la estructura de sus datos, esto podría tener un gran impacto en el rendimiento.
Vinci
fuente
0

Hice un punto de referencia rápido para comparar la velocidad de codificación y decodificación de MessagePack vs BSON. BSON es más rápido al menos si tiene matrices binarias grandes:

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

Usando C # Newtonsoft.Json y MessagePack por neuecc:

    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);
    }
itix
fuente
0

Bueno, como dijo el autor, MessagePack está diseñado originalmente para la comunicación en red, mientras que BSON está diseñado para almacenamientos.

MessagePack es compacto, mientras que BSON es detallado. MessagePack está diseñado para ahorrar espacio, mientras que BSON está diseñado para CURD (tiempo eficiente).

Lo más importante, el sistema de tipos de MessagePack (prefijo) sigue la codificación de Huffman, aquí dibujé un árbol Huffman de MessagePack (haga clic en el enlace para ver la imagen):

Huffman Tree of MessagePack

Jim
fuente