Table of Contents
Las arquitecturas impulsadas por eventos dependen del flujo fiable y consistente de datos entre productores y consumidores. A medida que evolucionan los sistemas, la estructura de los datos de eventos - sus cambios inevitables. Nuevos campos se añaden, los campos antiguos se desprecatan y a veces se cambian los modelos de datos completos. Sin una estrategia deliberada para gestionar estos cambios, los sistemas impulsados por eventos pueden llegar a ser frágiles, desencadenando errores de de de de deserialización, pérdida de información, o de datos de la disciplina.
Comprender la versión de los eventos
La versión de eventos es la práctica de identificar y rastrear versiones distintas de un esquema de eventos para que los productores y consumidores puedan coexistir en diferentes etapas de la evolución.El objetivo principal es asegurar que los eventos puedan ser interpretados correctamente independientemente de cuándo fueron producidos o por qué versión de un productor. Esto requiere tanto compatibilidad posterior] (los nuevos consumidores pueden leer los eventos producidos por los antiguos productores) y
La versión puede aplicarse en diversos niveles:
- Versión de esquema] – La definición de esquema en sí misma lleva un identificador de versión (por ejemplo, ). Este es el enfoque más explícito y funciona bien con registros de esquemas.
- Versión de carga] – La carga útil del evento incluye un campo de versión (por ejemplo, ) que le dice al consumidor qué esquema utilizar para la desserialización.
- Versión metadata] – La información de la versión se almacena en los encabezados de mensajes o metadatos en sobre, separados de la carga útil. Esto mantiene la carga útil limpia pero requiere que el consumidor pare el encabezado antes de leer el cuerpo.
Cada enfoque tiene cambios. La versión de Schema centraliza la gestión del esquema y facilita la compatibilidad, pero a menudo requiere búsquedas de registro de esquemas de tiempo de ejecución. La versión de payload es simple de implementar y funciona en sistemas sin registro, pero puede hinchar la carga útil y requiere un manejo cuidadoso de los campos de la versión. La versión de Metadata mantiene el esquema de carga limpia pero añade complejidad a la versión de metada inicial de los consumidores.
Estrategias para la evolución del esquema
La evolución del esquema es el conjunto de reglas y prácticas que rigen cómo los esquemas cambian con el tiempo preservando la compatibilidad. Las siguientes estrategias forman la base de un plan de evolución del esquema robusto.
Validación de Schema
Utilizar un lenguaje y una herramienta de validación de la definición de esquemas formales para hacer cumplir las reglas de la estructura de datos. Las opciones más populares son JSON Schema, Apache Avro] y Protocol Buffers (Protobuf). Estos idiomas proporcionan mecanismos integrados para la evolución, tales como valores predeterminados, campos opcionales y modos de compatibilidad.
Compatibilidad de retroceso
Un cambio de esquema es compatible con el atraso si un consumidor escrito para el nuevo esquema todavía puede leer los eventos producidos por el viejo esquema. Las técnicas más comunes incluyen:
- Adicionar campos opcionales] – Los nuevos campos deben ser opcionales con defectos sensibles (por ejemplo, o un valor cero). Los viejos eventos simplemente omiten estos campos, y el consumidor utiliza el predeterminado.
- Añadiendo nuevos valores enum – Nuevos valores enum pueden ser añadidos siempre y cuando no rompan la lógica existente. Los consumidores deben manejar los valores desconocidos con gracia.
- El manejo de campos nulos – Cambiar un campo requerido a la opción opcional es compatible con el revés; el reverso es un cambio de ruptura.
- Usar promociones de tipo] – Ampliar un campo (por ejemplo, → , → ) es a menudo seguro, pero el estrechamiento puede causar pérdida de datos.
Compatibilidad futura
La compatibilidad anticipada garantiza que un consumidor mayor pueda leer los eventos producidos por un productor más nuevo. Esto es más difícil de lograr porque el consumidor no sabe sobre los campos que no ha sido programado para esperar.
- Lectores tolerantes] – Los consumidores deben ignorar campos desconocidos durante la desserialización. La mayoría de los formatos de esquemas apoyan esto: Opción de Avro , Protobuf y preservación de campo desconocida, y JSON Schema .
- Valores predeterminados para nuevos campos – Los productores pueden poblar nuevos campos con valores predeterminados cuando el consumidor no puede utilizarlos, pero esto es realmente una preocupación de compatibilidad atrasada. Para la compatibilidad futura, el consumidor debe sobrevivir viendo campos que no entiende.
- Evitar cambios estructurales] – Renombrar campos, cambiar tipos o reorganizar estructuras anidadas normalmente rompe la compatibilidad. Tales cambios requieren una nueva versión de evento.
Versioning in Metadata
La versión de la versión de la versión en cabeceras de mensajes o un envoltorio de sobres descodifica la versión del esquema de carga útil. Un patrón común es utilizar un encabezado en Apache Kafka encabezados o un campo en un objeto envolvente. Este enfoque permite a los productores y consumidores manejar la resolución de esquemas en la capa de aplicación sin modificar el esquema de carga útil en sí.
Registros de Schema
Un registro de esquemas es un servicio centralizado que almacena y valida los esquemas en múltiples versiones. Ejecuta las reglas de compatibilidad (por ejemplo, atrasado, adelante, completo o ninguno) y proporciona una manera para que los consumidores recuperen el esquema necesario para desartizar un evento. Confluente Registro de Schema es el sistema más utilizado para Kafka-source check
Aplicación de la versión en la práctica
Para avanzar de la teoría a la implementación se requiere tomar decisiones concretas sobre formatos de serialización, herramientas y procesos. Las siguientes prácticas han sido probadas en sistemas de alta velocidad, impulsados por eventos de producción.
Elegir un formato de serialización
El formato de serialización determina cómo se definen los esquemas, cómo evolucionan y qué compatibilidad garantiza que obtiene. Aquí hay una comparación de las tres opciones principales:
- Apache Avro] – Diseñado para la evolución del esquema. Admite modos de compatibilidad atrasados, hacia adelante y completos. Utiliza un formato binario compacto con un marcado fuerte. Bien integrado con el Registro de Schema Confluente. Mejor para los ecosistemas de Kafka con sede en Java.
- Protocol Buffers (Protobuf)] – También apoya la evolución a través de números de campo y campos opcionales. Más eficiente que Avro para algunas cargas de trabajo. Funciona bien en sistemas de poliglotas con GRPC. Las reglas de compatibilidad son menos incorporadas pero se pueden aplicar con herramientas de terceros como Buf.
- JSON Schema] – Human-readable, ampliamente soportado, y fácil de depurar. No se incorpora en la serialización binaria; normalmente se utiliza con JSON. La evolución se administra a través de la especificaciones (por ejemplo, ]], ).
En muchas organizaciones, la opción ya está limitada por la infraestructura existente. Si estás empezando de nuevo, Avro ofrece la cadena de herramientas de evolución de esquemas más madura para la transmisión de eventos, mientras que Protobuf es un fuerte contendiente para la comunicación de microservicios.
Mantener la compatibilidad de las métricas
A medida que crece el número de esquemas y versiones, se hace esencial documentar qué versiones son compatibles con las cuales. Una matriz de compatibilidad mapea versiones de productor esquemas a versiones de esquemas de consumo, destacando cualquier incompatibilidad conocida. Esta matriz se puede mantener como un archivo YAML en su repositorio de esquemas o generado automáticamente por un registro de esquemas. Sirve como una herramienta de comunicación para equipos y una fuente de verdad para pruebas automatizadas.
Por ejemplo, una matriz podría registrar que es compatible con pero no compatible con el futuro, lo que significa que los consumidores antiguos romperán si reciben eventos v2. Esto obliga a una salida coordinada: o todos los consumidores se actualizan antes de que cualquier productor publique v2, o el productor continúa enviando eventos v1 hasta que la flota de consumidores esté lista.
Pruebas de compatibilidad automatizante
Comprobaciones manuales para la compatibilidad con esquemas rápidamente se vuelven inmanejables. Integrar validación de esquemas y comprobaciones de compatibilidad en su tubería CI/CD. Cada vez que un productor cambia un esquema, el oleoducto debe:
- Registrar el nuevo esquema contra el registro de esquemas con un modo de compatibilidad especificado.
- Si el registro falla, aborta la compilación y requiere que el equipo corrija el esquema (o pulverice explícitamente la versión del evento).
- Ejecute pruebas de integración con los consumidores reales que ejercen el nuevo esquema para capturar problemas de tiempo de ejecución.
- Si es exitoso, publicar la nueva versión de esquema junto con una entrada de cambio.
Herramientas como El plugin de Maven de Confluente] o scripts de shell de base (y ahora GitHub Actions) pueden automatizar esto. Para Protobuf, el comando Buf CLI proporciona un comando robusto que hace cumplir las reglas de compatibilidad.
Comunicación y documentación
Los cambios de Schema son contratos de API implícitos. Deben ser comunicados como cualquier otro cambio de API. Mantener un cambio de tipo de evento, observando lo que cambió, por qué, y qué garantías de compatibilidad aplican. Utilice una herramienta de documentación de esquema (por ejemplo, Backstage, un sitio generado de su registro de esquemas) para que los equipos puedan navegar por los esquemas disponibles y su historia.
Manejo de cambios de ruptura
A pesar de los mejores esfuerzos para evitarlos, a veces deben ocurrir cambios de ruptura (por ejemplo, renombrar un campo, cambiar un tipo de datos, reestructurar objetos anidados). Cuando lo hacen, usted tiene tres opciones principales:
- Temas versados] – Producir eventos sobre un nuevo tema (por ejemplo, ) mientras que los consumidores viejos continúan leyendo desde el viejo tema. Esto es limpio pero duplica la infraestructura y requiere que los consumidores se suscriban a ambos temas durante la migración.
- Evento versión paragolpes] – Mantenga el mismo tema pero aumente el número de versión principal del evento. Los consumidores deben revisar la versión y decidir cómo deserializar. Esto evita la proliferación de temas pero añade lógica de ramificación en los consumidores.
- Dual escribe] – Durante un período de transición, el productor emite tanto los formatos antiguos como los nuevos eventos. Esto se utiliza a menudo como una piedra de paso mientras los consumidores son migrados. Duplica el tráfico y aumenta la complejidad, por lo que debe ser temporal.
Cualquier camino que elijas, siempre empareja el cambio de ruptura con una clara política de deprecación y una puesta en marcha monitorizada.
Consideraciones avanzadas
Cuando la versión de eventos y la evolución del esquema se intersecten con la fuente de eventos, entornos de poliglotas o tiendas especializadas de eventos, surgen matices adicionales.
Sourcing y Evolución del Schema
En sistemas de fuente de verdad, los eventos son fuente de verdad y nunca se eliminan o alteran. La evolución de esquema se convierte en una preocupación de diseño crítico porque cada evento pasado debe permanecer interpretable para siempre. La práctica recomendada es almacenar eventos en un formato que apoye la evolución del esquema nativamente (por ejemplo, Avro o Protobuf con un registro de esquemas mutantes) y siempre añadir campos con defectos en lugar de modificar los existentes.
Versioning in Polyglot Environments
Cuando los productores y consumidores se escriben en diferentes idiomas, debe asegurarse de que el formato de serialización y la definición de esquema son consistentes en todos los idiomas. Avro y Protobuf tienen una generación de código robusta para muchos idiomas, pero cada idioma puede manejar campos desconocidos o valores predeterminados ligeramente diferentes. Prueba compatibilidad de lenguajes cruzados temprano en desarrollo. Utilice un registro de esquemas que proporciona serializadores de lenguaje-agnóstico (por ejemplo, RESTxy
Versión con Event Stores
Sistemas como EventStoreDB o Apache Kafka (utilizados como una tienda de eventos) a menudo tienen sus propios mecanismos para la gestión de esquemas. EventStoreDB admite tipos de eventos y proyecciones, pero la evolución del esquema sigue siendo su responsabilidad. Con Kafka, el registro del esquema es la herramienta principal. Sin embargo, cuando se utiliza Kafka como una tienda de eventos a largo plazo, considere agregar una política de retención que compacta o borra los eventos antiguos sólo después de los consumidores
Conclusión
La versión de eventos y la evolución del esquema no son opcionales en ningún sistema impulsado por eventos que espera vivir más allá de un único ciclo de liberación. Al adoptar registros de esquemas, elegir el formato de serialización adecuado, y automatizar cheques de compatibilidad, los equipos pueden evolucionar sus esquemas de datos con confianza. La compatibilidad posterior y avanzada protege a los consumidores de fracasos inesperados, mientras que las políticas claras de comunicación y deprecación mantienen a todos alineados.