Las arquitecturas orientadas a eventos y aplicaciones de datos en tiempo real son cada vez más demandadas y Apache Kafka o Confluent se han convertido en la pieza central de dichas soluciones.

En el blog ya se ha hablado anteriormente de las funcionalidades de Kafka, así como de alguno de sus componentes principales como Kafka Streams.

En este caso, vamos a hablar en profundidad del Schema Registry de Kafka, en qué se basa su funcionamiento y cómo utilizarlo de una manera adecuada para gobernar eventos. Si quieres entender mejor la evolución de los esquemas, pero de forma práctica interactuando con Kafka, no te pierdas este artículo.

¿Por qué se necesita un Schema Registry?

Si pensamos en plataformas de streaming de datos, la volumetría de información que se maneja y la cantidad de componentes que las conforman, para su gestión y crecimiento se necesitan ciertas garantías. Estas garantías las proporciona el Schema Registry.

La filosofía de Kafka, y parte fundamental del éxito de su funcionamiento, es que toma bytes de información y los publica a los consumidores, no lee esos datos, no los carga en memoria, ni realiza ninguna verificación de los mismos.

Teniendo en cuenta esto, nos surgen algunas dudas:

Para dar solución a estos problemas se hace uso de esquemas para los mensajes que se envían. Si pensamos en un ecosistema de aplicaciones de tipo petición / respuesta las APIs son un punto clave, y en un mundo asíncrono los esquemas de los mensajes son las APIs entre productores y consumidores.

El Schema Registry es un componente independiente de Kafka que tiene los siguientes objetivos:

¿Cómo funciona el Schema Registry?

En Kafka el desacoplamiento entre los productores y consumidores implica que no se comuniquen entre sí, sino a través de un topic. El consumidor necesita saber qué tipo de datos envió el productor para deserializarlos y el productor para serializarlos y enviárselos al consumidor como espera. Para esto se utiliza el Schema Registry, cuyo funcionamiento es el siguiente:

El productor, antes de enviar los datos a Kafka se comunica con el Schema Registry y verifica si el esquema está disponible.

El consumidor recibe el mensaje de Kafka y se comunica con el Schema Registry utilizando el identificador de esquema recibido y deserializa los datos utilizando dicho esquema. Si hay alguna discrepancia o problema al deserializar el Schema Registry lanzará un error indicando que se ha incumplido el contrato especificado.

El uso de este componente tiene como principales ventajas:

¿Qué es AVRO?

Avro es un formato de serialización de datos binarios open source con el que se pueden representar estructuras de datos complejas. Sus principales características son:

Las principales ventajas del uso de este formato son:

Las principales desventajas son que los datos no pueden visualizarse sin utilizar herramientas que lean Avro y que ciertos lenguajes no tienen librerías ni herramientas que ayuden a su procesamiento.

Un ejemplo de un esquema en Avro es el siguiente:

{"namespace": "test.avro",
 "type": "record",
 "name": "LogLine",
 "fields": [
   {"name": "ip", "type": "string"},
   {"name": "url",  "type": "string"},
   {"name": "referrer",  "type": "string"},
   {"name": "userAgent",  "type": "string"},
   {"name": "sessionId",  "type": ["null","string"], "default": null}
 ]
}

Volviendo al ecosistema de Kafka y al Schema Registry, Avro se utiliza como uno de los posibles formatos de datos para especificar la estructura de la información que se envía a través de un topic de kafka. Aunque también es posible hacerlo con JSON Schema y Protobuf, en este caso utilizaremos el formato clásico de Avro que nos permite:

¿Cómo evolucionan los esquemas?

Una parte fundamental de la gestión y el gobierno de eventos es la evolución de los esquemas. Una vez que se establece un esquema inicial, las aplicaciones y los requerimientos de negocio cambian y resulta crítico que los componentes que utilizan el antiguo esquema sigan funcionando. Independientemente de si se utiliza Avro u otro formato es necesario considerar cómo evolucionan dichos esquemas.

El Schema Registry está diseñado para verificar la compatibilidad entre esquemas a través de la versión y del tipo de compatibilidad.

La gestión de las versiones es muy sencilla. El esquema inicial es representado en la versión 1 y las sucesivas evoluciones serán las versiones 2, 3, etc. Para generar una nueva versión el Schema Registry compara si se cumple el tipo de compatibilidad establecida y si se cumple se genera la siguiente versión.

Los tipos de compatibilidades, es decir, los cambios permitidos entre versiones de un mismo esquema son los siguientes:

1 Compatibilidad forward

Es el patrón más común, en el que se quiere actualizar un productor porque el flujo de datos evoluciona y los consumidores no se actualizan.

En este caso el consumidor utiliza el antiguo esquema (v1) para leer los nuevos datos de un productor que los genera con el nuevo esquema (v2).

Si utilizamos como ejemplo el mismo esquema Avro de un línea de log que hemos visto antes y se configura la compatibilidad forward se observa lo siguiente:

2 Compatibilidad backward

Es el patrón menos habitual, en el que se quiere actualizar el flujo de datos teniendo nuevos consumidores que los procesan pero todavía hay productores que no se van a actualizar.

En este caso el consumidor utiliza el nuevo esquema (v2) para leer los datos de un productor que los genera con el antiguo esquema (v1).

Si volvemos al ejemplo de nuestro esquema Avro de un línea de log y se configura la compatibilidad backward se observa lo siguiente:

3 Compatibilidad completa o full

Es el patrón ideal y cumple las compatibilidades forward y backward. En el que se quiere actualizar el flujo de datos y se pueden actualizar tanto productores como consumidores y consumir o producir información en ambas versiones.

Si volvemos al ejemplo de nuestro esquema Avro y se configura la compatibilidad full y se cambia el esquema inicial (v1) añadiendo un nuevo campo con valor por defecto (message) y se elimina un campo opcional (sessionId) en el esquema evolucionado (v2) se tiene lo siguiente:

4 Breaking o incompatible

Es el patrón a evitar, pero que a veces es inevitable. Esto sucede cuando el flujo de datos nuevo tiene un esquema que rompe la versión anterior.

Conclusiones

Cuéntanos qué te parece.

Enviar.

Los comentarios serán moderados. Serán visibles si aportan un argumento constructivo. Si no estás de acuerdo con algún punto, por favor, muestra tus opiniones de manera educada.

Suscríbete

Estamos comprometidos.

Tecnología, personas e impacto positivo.