protocol-buffers thrift asn.1 avro

¿Cuáles son las principales diferencias entre Apache Thrift, Google Protocol Buffers, MessagePack, ASN.1 y Apache Avro?



protocol-buffers (6)

Añadiendo a la perspectiva del rendimiento, Uber recientemente evaluó varias de estas bibliotecas en su blog de ingeniería:

https://eng.uber.com/trip-data-squeeze/

El ganador para ellos? MessagePack + zlib para compresión

Nuestro objetivo era encontrar la combinación de protocolo de codificación y algoritmo de compresión con el resultado más compacto a la velocidad más alta. Probamos el protocolo de codificación y las combinaciones de algoritmos de compresión en 2,219 viajes anonimizados pseudoaleatorios desde Uber, ciudad de Nueva York (colocamos un archivo de texto como JSON).

La lección aquí es que sus requisitos determinan qué biblioteca es la adecuada para usted. Para Uber no podían usar un protocolo basado en IDL debido a la naturaleza sin esquema del mensaje que pasaban. Esto eliminó un montón de opciones. También para ellos no solo entra en juego el tiempo de codificación / decodificación en bruto, sino también el tamaño de los datos en reposo.

Resultados de tamaño

Resultados de velocidad

Todos estos proporcionan serialización binaria, marcos RPC e IDL. Me interesan las diferencias clave entre ellos y las características (rendimiento, facilidad de uso, compatibilidad con los lenguajes de programación).

Si conoce alguna otra tecnología similar, mencionela en una respuesta.


Acabamos de hacer un estudio interno sobre serializadores, aquí hay algunos resultados (¡para mi futura referencia también!)

Thrift = serialización + pila RPC

La mayor diferencia es que Thrift no es solo un protocolo de serialización, es una pila RPC completa que es como una pila SOAP moderna. Por lo tanto, después de la serialización, los objetos podrían enviarse (pero no obligatoriamente) entre máquinas a través de TCP / IP. En SOAP, comenzó con un documento WSDL que describe completamente los servicios disponibles (métodos remotos) y los argumentos / objetos esperados. Esos objetos fueron enviados a través de XML. En Thrift, el archivo .thrift describe completamente los métodos disponibles, los objetos de parámetros esperados y los objetos se serializan a través de uno de los serializadores disponibles (con Compact Protocol , un protocolo binario eficiente, siendo el más popular en producción).

ASN.1 = Grand Daddy

ASN.1 fue diseñado por personas de telecomunicaciones en los años 80 y es incómodo de usar debido al limitado soporte de la biblioteca en comparación con los serializadores recientes que surgieron de la gente de CompSci. Hay dos variantes, codificación DER (binaria) y codificación PEM (ascii). Ambos son rápidos, pero DER es más rápido y más eficiente en tamaño de los dos. De hecho, ASN.1 DER puede fácilmente mantener (y algunas veces superar) los serializadores que fueron diseñados 30 años después de sí mismo, un testimonio de su diseño bien diseñado. Es muy compacto, más pequeño que Protocol Buffers y Thrift, solo superado por Avro. El problema es tener grandes bibliotecas para apoyar y ahora Bouncy Castle parece ser el mejor para C # / Java. ASN.1 es el rey en sistemas de seguridad y criptografía, y no va a desaparecer, así que no te preocupes por las "pruebas futuras". Solo consigue una buena biblioteca ...

MessagePack = medio del paquete

No está mal pero no es ni el más rápido, ni el más pequeño ni el mejor compatible. Sin motivo de producción para elegirlo.

Común

Más allá de eso, son bastante similares. La mayoría son variantes del TLV: Type-Length-Value básico TLV: Type-Length-Value principio de TLV: Type-Length-Value .

Los búferes de protocolo (originado en Google), Avro (basado en Apache, utilizado en Hadoop), Thrift (originado en Facebook, ahora proyecto Apache) y ASN.1 (originado en Telecom) implican algún nivel de generación de código donde primero expresas tus datos en un serializador formato específico, luego el "compilador" del serializador generará el código fuente para su idioma a través de la fase de code-gen . El origen de su aplicación utiliza estas clases de code-gen para IO. Tenga en cuenta que ciertas implementaciones (por ejemplo, la biblioteca Avro de Microsoft o ProtoBuf.NET de Marc Gavel) le permiten decorar directamente los objetos POCO / POJO de su aplicación y luego la biblioteca usa directamente esas clases decoradas en lugar de las clases de código gen. Hemos visto que esto ofrece un rendimiento de impulso ya que elimina una etapa de copia de objeto (desde campos POCO / POJO a nivel de aplicación a campos genéricos de código).

Algunos resultados y un proyecto en vivo para jugar con

Este proyecto ( https://github.com/sidshetye/SerializersCompare ) compara serializadores importantes en el mundo de C #. La gente de Java ya tiene algo similar .

1000 iterations per serializer, average times listed Sorting result by size Name Bytes Time (ms) ------------------------------------ Avro (cheating) 133 0.0142 Avro 133 0.0568 Avro MSFT 141 0.0051 Thrift (cheating) 148 0.0069 Thrift 148 0.1470 ProtoBuf 155 0.0077 MessagePack 230 0.0296 ServiceStackJSV 258 0.0159 Json.NET BSON 286 0.0381 ServiceStackJson 290 0.0164 Json.NET 290 0.0333 XmlSerializer 571 0.1025 Binary Formatter 748 0.0344 Options: (T)est, (R)esults, s(O)rt order, (S)erializer output, (D)eserializer output (in JSON form), (E)xit Serialized via ASN.1 DER encoding to 148 bytes in 0.0674ms (hacked experiment!)


Bond de Microsoft ( https://github.com/Microsoft/bond ) es muy impresionante con rendimiento, funcionalidades y documentación. Sin embargo, no es compatible con muchas plataformas de destino a partir de ahora (13 de febrero de 2015). Solo puedo suponer que es porque es muy nuevo. actualmente es compatible con python, c # y c ++. Está siendo utilizado por MS en todas partes. Lo intenté, para mí, ya que ac # desarrollador usando bond es mejor que usar protobuf; sin embargo, también he usado el ahorro, el único problema al que me enfrenté fue con la documentación, tuve que probar muchas cosas para entender cómo se hacen las cosas.

Pocos recursos en Bond son los siguientes ( https://news.ycombinator.com/item?id=8866694 , https://news.ycombinator.com/item?id=8866848 , https://microsoft.github.io/bond/why_bond.html )


Lo más importante de ASN.1 es que está diseñado para especificación, no implementación. Por lo tanto, es muy bueno para ocultar / ignorar detalles de implementación en cualquier lenguaje de programación "real".

Es tarea del compilador ASN.1 aplicar las Reglas de codificación al archivo asn1 y generar a partir de ambos código ejecutable. Las Reglas de Codificación pueden ser dadas en Notación EnCoding (ECN) o pueden ser una de las estandarizadas como BER / DER, PER, XER / EXER. Eso es ASN.1 es los Tipos y Estructuras, las Reglas de Codificación definen la codificación en el cable y, por último, el Compilador lo transfiere a su lenguaje de programación.

Los compiladores libres son compatibles con C, C ++, C #, Java y Erlang que yo sepa. Los compiladores comerciales (mucho costosos y patentados / con licencia) son muy versátiles, usualmente absolutamente actualizados y admiten a veces incluso más idiomas, pero pueden ver sus sitios (OSS Nokalva, Marben, etc.).

Es sorprendentemente fácil especificar una interfaz entre partes de culturas de programación totalmente diferentes (por ejemplo, personas "integradas" y "agricultores de servidores") utilizando estas técnicas: un archivo asn.1, la regla de codificación, por ejemplo, BER y un diagrama de interacción UML, por ejemplo . No se preocupe por cómo se implementa, ¡que todos usen "lo suyo"! Para mí, ha funcionado muy bien. Por cierto: en el sitio de OSS Nokalva, puede encontrar al menos dos libros de descarga gratuita sobre ASN.1 (uno de Larmouth y el otro de Dubuisson).

En mi humilde opinión, la mayoría de los demás productos solo intentan ser todavía, otro RPC-stub-generators, que inyecta una gran cantidad de aire en el problema de la serialización. Bueno, si uno necesita eso, uno podría estar bien. Pero para mí, parecen reinvenciones de Sun-RPC (desde finales de los 80), pero, oye, eso funcionó bien también.


Para el rendimiento, un punto de datos es el punto jvm-serializers referencia de los jvm-serializers : es un mensaje bastante específico y pequeño, pero podría ser útil si se está en la plataforma Java. Creo que el rendimiento en general a menudo no será la diferencia más importante. Además: NUNCA tome las palabras de los autores como evangelio; muchas afirmaciones publicitadas son falsas (el sitio msgpack, por ejemplo, tiene algunas afirmaciones dudosas, puede ser rápido, pero la información es muy incompleta, el caso de uso no es muy realista).

Una gran diferencia es si se debe usar un esquema (PB, al menos Thrift; Avro puede ser opcional; ASN.1, creo que también; MsgPack, no necesariamente).

Además: en mi opinión, es bueno poder usar un diseño modular en capas; es decir, la capa RPC no debe dictar el formato de datos ni la serialización. Desafortunadamente, la mayoría de los candidatos lo hacen de forma muy ajustada.

Finalmente, al elegir el formato de datos, hoy en día el rendimiento no excluye el uso de formatos de texto. Hay analizadores de JSON increíblemente rápidos (y analizadores de xml de transmisión bastante rápidos); y cuando se considera la interoperabilidad de los lenguajes de scripting y la facilidad de uso, los formatos y protocolos binarios pueden no ser la mejor opción.


ASN.1 es un estándar ISO / ISE. Tiene un lenguaje de origen muy legible y una variedad de back-ends, tanto binarios como legibles para los humanos. Al ser un estándar internacional (¡y uno antiguo!), El idioma de origen es un poco insatisfactorio (casi de la misma manera que el Océano Atlántico está un poco húmedo) pero está muy bien especificado y tiene una cantidad decente de soporte . (Probablemente pueda encontrar una biblioteca ASN.1 para cualquier idioma que nombre si excavar lo suficiente, y si no hay buenas bibliotecas de lenguaje C disponibles que puede usar en FFI). Es, al ser un lenguaje estandarizado, obsesivamente documentado y tiene algunos buenos tutoriales disponibles también.

Thrift no es un estándar. Es originario de Facebook y luego fue de código abierto y actualmente es un proyecto Apache de primer nivel. No está bien documentado, especialmente los niveles de tutoriales, y para mi (por cierto breve) vistazo no parece agregar nada que otros esfuerzos anteriores ya no hacen (y en algunos casos mejor). Para ser justos, tiene una cantidad bastante impresionante de idiomas que admite de manera inmediata, incluidos algunos de los no convencionales más importantes. El IDL también es vagamente similar a C.

Protocol Buffers no es un estándar. Es un producto de Google que se lanza a la comunidad en general. Es un poco limitado en términos de idiomas admitidos de fábrica (solo admite C ++, Python y Java), pero tiene una gran cantidad de compatibilidad con terceros para otros idiomas (de calidad muy variable). Google hace prácticamente todo su trabajo utilizando Protocol Buffers, por lo que es un protocolo probado y probado en la batalla (aunque no tan endurecido como ASN.1. Tiene mucha mejor documentación que Thrift, pero al ser un Producto de Google, es muy probable que sea inestable (en el sentido de siempre cambiante, no en el sentido de no confiable). El IDL también tiene forma de C.

Todos los sistemas anteriores usan un esquema definido en algún tipo de IDL para generar código para un idioma de destino que luego se utiliza en codificación y decodificación. Avro no. La tipificación de Avro es dinámica y sus datos de esquema se usan directamente en tiempo de ejecución para codificar y decodificar (lo que tiene algunos costos evidentes en el procesamiento, pero también algunos beneficios obvios frente a los lenguajes dinámicos y la falta de tipos de etiquetado, etc.) . Su esquema usa JSON, lo que hace que sea más fácil administrar Avro en un nuevo idioma si ya hay una biblioteca JSON. Nuevamente, como con la mayoría de los sistemas de descripción de protocolo de reinvención de ruedas, Avro tampoco está estandarizado.

Personalmente, a pesar de mi relación de amor / odio con él, probablemente usaría ASN.1 para la mayoría de los propósitos de transmisión de mensajes y RPC, aunque en realidad no tiene una pila de RPC (tendría que hacer uno, pero los IOC lo hacen Suficientemente simple).