colombia-dev / bookclub

Grupo de Lectura de ColombiaDev
38 stars 0 forks source link

Designing Data-Intensive Applications: 4. Encoding and Evolution #7

Open guilleiguaran opened 5 years ago

guilleiguaran commented 5 years ago

Esta semana a cargo @julianduque Siguiente semana @fmauricios

julianduque commented 5 years ago

El summary lo estaré publicando el domingo, esta semana tuve cirugía y ando lento ;)

julianduque commented 5 years ago

Capítulo 4 - Encoding y Evolución

Conceptos Claves

Cuando el formato de los datos cambia se debe hacer cambio del código pero no siempre se puede hacer inmediatamente.

Viejas y nuevas versiones del código y los datos pueden existir al mismo tiempo, por eso de debe garantizar compatibilidad en ambas vías

Backwards compatibility usualmente no es dificil pues se conoce la forma de datos anterior. Forward compatibility es dificil pues el código debe ignorar adiciones a los datos en nuevas versiones del código.

Formatos de Encoding

Aplicaciones usualmente trabajan con datos en dos representaciones:

El proceso de tradución de la data en memoria hacia una secuencia de bytes se conoce como codificación (encoding, serialización o marshalling). El proceso inverso se conoce como decodificación (decoding, parsing, deserialization, unmarshalling).

Formatos específicos de un lenguaje

Varios lenguajes tienen sus propios formatios para codificación:

Aunque pueden llegar a ser convenientes tienen sus limitaciones:

Conclusión: Evitar usar este tipo de formatos, solo para cosas pequeñas / no importantes.

JSON, XML y CSV

JSON, XML y CSV son formatos de codificación de tipo texto, bastante populares, de alguna u otra forma legibles (human readable) y con una síntaxis no muy poderosa.

Algunos de los problemas relacionados con estos formatos:

A pesar de sus fallas, son suficientemente buenos para la mayoría de aplicaciones siempre y cuando se mantenga un formato definido.

Codificación Binaria

Son formatos mas compactos y rápidos de parsear, óptimos para grandes cantidades de información (mejor performance) y recomendados para uso interno dentro de una organización. Aunque son utilizados no son tan populares como sus versiones basadas en texto.

Algunos de estos formatos poseen tipos de datos cono enteros, punto flotante, strings binarios, etc, pero, al no tener un schema definido deben incluir también el nombre de las propiedades dentro de la data codificada.

MessagePack por ejemplo utiliza secuencias de byte para identificar los tipos de datos y el tamaño de la información que va a codificar, permitiendo así tener reducciones de tamaño de la información.

Thrift y Protocol Buffers

Apache Thrift (Desarrollada originalmente por Facebook) y Protocol Buffers (Desarrollada por Google) son tecnologías open source para codificar datos de manera binaria, ambos requieren un Schema para cualquier tipo de información que será codificada. Usualmente utiliza un IDL (Interface Definition Language) para definir el Schema, ejemplo:

Thrift

struct Person {
    1: required string         userName,
    2: optional i64            favoriteNumber,
    3: optional list<string>   interests
}

Protobuf

message Person {
    required string user_name       = 1;
    optional int64 favorite_number  = 2;
    repeated string interests       = 3;
}

Ambas tecnologías cuentan con herramientas para generar código a partir del Schema.

Thrift cuenta con dos tipos de codificación: BinaryProtocol y CompactProtocol, en este caso en el proceso de codificación no se utiliza el nombre de los campos como en MessagePack sino que se utiliza un field tag (aliases), el cual correspondería al número que aparece en el esquema. La principal diferencia entre BinaryProtocol y CompactProtocol es que este último codifica en un solo byte el field tag y el tipo de dato y también utiliza tamaño variable para enteros.

Protocol Buffers solo utiliza un tipo de codificación binaria utilizando un método muy similar a CompactProtocol de Thrift.

Aunque en el Schema se definan campos requeridos estos no interfieren en el proceso de codificación, solamente es utilizado en runtime como un check de validación.

Los field tags son clave para el tema de la evolución de los Schema, siempre y cuando se conserve el mismo identificador de campo (field tag) el código será capaz de interpretar la información correctamente. En el caso de backwards compatibility, nuevos campos no pueden ser requeridos y tampoco se pueden eliminar campos que sean requeridos, solo aquellos que son opcionales. Respecto al cambio de tipo de dato, aunque algunos protocolos lo pueden soportar no es recomendado pues se puede perder información.

Avro

Apache Avro es otro formato de codificación binaria, diferente a Thrift y Protocol Buffers, nace en 2009 como un sub-proyecto de Hadoop.

Avro utiliza un schema para definir la estructura de los datos y se puede escribir en dos lenguajes: Avro IDL y JSON.

Avro IDL

record Person {
    string                  userName;
    union { null, long }    favoriteNumber = null;
    array<string>           interests;
}

Avro JSON

{
    "type": "record",
    "name": "Person",
    "fields": [
        { "name": "userName", "type": "string" },
        { "name": "favoriteNumber", "type": ["null", "long"], "default": null },
        { "name": "interests", "type": "array", "items": "string" }
    ]
}

Avro no utiliza field tags o identificadores de tipo, simplemente codifica los valores concatenados uno del otro. Un string consiste en su tamaño seguido de la información en UTF-8. Un entero se codifica como Thrift CompactProtocol utilizando tamaño variable.

Avro decodifica la información utilizando el orden de los campos según aparecen en el esquema, de tal manera que el mismo esquema debe ser usado por ambas partes o sino Avro no es capaz de realizar el proceso correctamente.

Para temas de Evolución de Schema, Avro utiliza el esquema de escritura y el esquema de escritura, estos no tienen que ser exactamente el mismo pero deben ser compatibles, Avro realiza un proceso de traducción del esquma de escritura al esquema de lectura.

Para mantener compatibilidad y evolución solo se pueden quitar y agregar campos que tengan un valor por defecto.

Cómo el lector (reader) conoce sobre el esquema de escritura (writers)? Depende del contexto en el cual se utilice Avro:

  1. Un archivo grande con muchos registros: Se puede incluir el esquema al inicio del archivo y de esta forma el lector sabe con que esquema se escribieron los registros
  2. Base de datos con registros individuales: Se puede incluir un campo con la versión del esquema utilizada para ese registro en especifico.
  3. Enviar registros por la red: Se puede enviar el esquema al inicio de la conexión (Así funciona Avro RPC)

Para aplicaciones grandes se recomienda tener una base de datos con diferentes esquemas y sus versiones, este puede actuar como documentación y mecanismo para verificar compatibilidad.

Avro también cuenta con mecanismos para generar esquemas dinámicamente facilitando el proceso de evolución.

Meritos de Esquemas

Modos de Flujo de Datos

Base de datos

Servicios (REST / RPC)

Web

RPC

guilleiguaran commented 5 years ago

Hace varios años Uber publico un interesante articulo sobre el tema: How Uber Engineering Evaluated JSON Encoding and Compression Algorithms to Put the Squeeze on Trip Data[1]

[1] https://eng.uber.com/trip-data-squeeze/