Evolución del esquema
Cambiar un esquema de eventos puede romper los productores, las consultas, los paneles, las alertas y las exportaciones que dependen de él. Telemetry acepta nuevos campos JSON sin una migración previa. Cambiar el tipo o el significado de un campo existente requiere un plan para el código y las filas almacenadas que usan la definición anterior.
Mantenga estables el significado y el tipo de cada campo existente. Introduzca un campo o una versión nueva si alguno debe cambiar.
Matriz de compatibilidad
| Cambio propuesto | Compatibilidad de ingestión | Compatibilidad de consultas | Enfoque recomendado |
|---|---|---|---|
| Agregar un campo opcional | Generalmente compatible | Las filas antiguas no devuelven ningún valor | Agregue, mida la adopción y luego actualice a los consumidores |
| Agregar un objeto anidado | Generalmente compatible | Las filas antiguas no tienen rutas anidadas | Mantenga cada ruta anidada escrita y estable |
| Agregar un valor de estado controlado | El tipo de datos es compatible | Los filtros exhaustivos pueden pasarlo por alto | Actualizar y probar a los consumidores antes de la emisión. |
| Dejar de enviar un campo opcional | Las filas pueden omitirlo. | Los consumidores ven valores faltantes | Desaprobar primero y medir los lectores restantes |
| Cambiar el nombre o mover un campo | Crea un campo diferente | Los antiguos consumidores siguen leyendo el nombre antiguo. | Escritura dual, migrar y luego retirarse |
| Cambiar número a cadena | Incompatible con el tipo establecido | Los cálculos ya no tienen un solo tipo. | Crear un nuevo campo escrito correctamente |
| Cambiar unidades sin cambiar el nombre | El tipo aún puede coincidir | Los resultados se vuelven silenciosamente incorrectos | Agregue un campo específico de la unidad como _ms |
| Cambiar el grano del evento | Las filas aún ingieren | Los recuentos y las uniones dejan de ser válidos | Publicar un nuevo nombre de evento o una versión principal |
Agregar datos es técnicamente fácil. La compatibilidad también depende de cada definición posterior, especialmente de los valores controlados, las unidades, el tamaño de las filas, la identidad y la semántica de tiempo.
Agregue un campo sin interrumpir a los consumidores
Supongamos que api_request_completed ya registra:
{
"event_id": "evt_api_01",
"route": "/v1/query/:id",
"status_code": 200,
"latency_ms": 184,
"release": "2026.07.2"
}
Quiere agregar una categoría de falla limitada:
{
"event_id": "evt_api_02",
"route": "/v1/query/:id",
"status_code": 503,
"latency_ms": 921,
"release": "2026.07.3",
"error_type": "upstream_unavailable"
}
Implementar en etapas:
- Documente los valores permitidos, la clase de privacidad, el propietario y la sucursal que establece el campo.
- Agregue un accesorio para un éxito sin
error_typey cada categoría de falla esperada. - Libere al productor mientras las consultas existentes sigan ignorando el campo.
- Mida la cobertura de campo por lanzamiento y estado.
- Actualice los paneles y las alertas solo después de que los contengan suficientes filas relevantes.
- Mantenga las consultas tolerantes a las filas más antiguas durante al menos la ventana de migración retenida.
El registro API elimina valores nulos, objetos vacíos y matrices vacías. Por lo tanto, "No presente" es el estado almacenado esperado para un campo opcional sin valor.
Medir la adopción antes de depender de un campo
Utilice la versión de lanzamiento o una versión de productor explícita para encontrar código parcialmente migrado:
SELECT
release,
COUNT(*) AS failed_requests,
SUM(CASE WHEN error_type IS NULL THEN 1 ELSE 0 END) AS missing_error_type,
100.0 * SUM(CASE WHEN error_type IS NULL THEN 1 ELSE 0 END)
/ NULLIF(COUNT(*), 0) AS missing_rate_pct
FROM api_request_completed
WHERE status_code >= 500
AND timestamp_utc >= now() - INTERVAL '24 hours'
GROUP BY release
ORDER BY release;
No utilice COALESCE(error_type, 'none') a menos que "ninguno" sea la categoría prevista para cada valor anterior y faltante. Puede ocultar una implementación fallida del productor.
Cambiar el nombre, mover o redefinir un campo
Cambiar el nombre de latency_ms a duration_ms no es un cambio de nombre local en los datos de eventos almacenados. Utilice una migración de doble escritura:
{
"latency_ms": 184,
"duration_ms": 184,
"schema_version": 2
}
Durante la ventana de migración, haga explícita la prioridad:
SELECT
route,
approx_percentile_cont(
COALESCE(duration_ms, latency_ms),
0.95
) AS p95_duration_ms
FROM api_request_completed
WHERE timestamp_utc >= now() - INTERVAL '7 days'
GROUP BY route;
Entonces:
- actualice cada consulta, panel, alerta, exportación y consumidor guardados;
- verificar que ningún productor actual envíe solo el campo antiguo;
- esperar hasta el período de compatibilidad acordado;
- deja de escribir el campo antiguo;
- mantenga documentado el comportamiento de consultas históricas para las filas antiguas retenidas.
Utilice schema_version cuando una consulta deba distinguir definiciones, no como sustituto de nombres de campos estables. Una versión es especialmente útil cuando el grano de la fila, el significado del resultado o una estructura anidada cambian juntos.
Nunca cambie el tipo de campo en su lugar
Este cambio no es seguro:
{ "account_id": 8421 }
{ "account_id": "acct_8421" }
El segundo productor entra en conflicto con un valor numérico account_id establecido por el primero. Incluso cuando la capa de almacenamiento pudiera representar ambos valores por separado, las uniones y los filtros ya no compartirían un tipo confiable.
Agregue un nuevo campo de cadena como account_key, rellene solo si tiene una asignación revisada y determinista y migre los consumidores. La misma regla se aplica a:
- duraciones numéricas enviadas como cadenas formateadas;
- booleanos reemplazados por
"yes"y"no"; - marcas de tiempo reemplazadas por cadenas específicas de la localidad;
- una ruta anidada que cambia de objeto a escalar;
- identificadores que cambian de un tipo de entidad a otro.
Trate los valores de estado como esquema
Agregar cancelled a un campo previamente documentado como success o failed no cambia su tipo de cadena, pero aún puede romper la lógica:
SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END)
La consulta trata silenciosamente a cancelled como si no hubiera fallado. Decida si el nuevo valor pertenece a una falla, exclusión o resultado separado antes de emitirlo. Busque en el registro de consultas filtros de estado exhaustivos y actualice los accesorios primero.
Validar la implementación y la reversión
Pruebe eventos representativos antes de la producción:
| Accesorio | lo que prueba |
|---|---|
| Éxito de la versión anterior | Las filas y consultas existentes aún funcionan |
| Éxito de la nueva versión | Los campos agregados tienen el tipo esperado |
| Fallo de la nueva versión | Los campos de solo error están presentes y limitados |
| Falta campo opcional | El manejo nulo sigue siendo intencional |
| Reintentar o duplicar | Los condes preservan el grano documentado |
| productor de reversión | Una implementación más antigua puede coexistir de forma segura |
Después de la implementación, compare el volumen de eventos aceptado, la cobertura de campos obligatorios, la distribución de valores controlados y los resultados de consultas clave por versión. Una reversión es segura sólo si el antiguo productor aún puede escribir el esquema establecido y los nuevos consumidores toleran los campos faltantes.
Datos históricos y reposiciones
La evolución del esquema cambia eventos futuros; no reescribe automáticamente el historial retenido. Antes de un relleno:
- definir la fuente exacta de la verdad y la transformación determinista;
- preservar la hora original del evento y los identificadores estables;
- evitar duplicados con un identificador de evento o migración;
- probar el recuento de filas y los totales agregados en un intervalo acotado;
- registrar qué fechas y versiones fueron reescritas;
- Decida si los paneles deben mostrar un historial mixto o reabastecido.
Si los datos antiguos no pueden respaldar el nuevo significado, déjelos omitidos y muestre un límite de cobertura. Inventar un valor produce un gráfico más limpio pero un análisis menos confiable.
Lista de verificación de cambio de esquema
- Indique el grano, los tipos, las unidades y los significados de las filas actuales y propuestas.
- Productores de inventario y todas las consultas, paneles, alertas y exportaciones posteriores.
- Prefiere un campo aditivo; utilice un nuevo evento o versión para un cambio de grano.
- Agregue accesorios de éxito, fracaso, falta, reintento y reversión.
- Implemente el lector compatible antes que el nuevo escritor cuando ambos deban cambiar.
- Mida la adopción por lanzamiento en lugar de asumir una implementación completa.
- Mantenga una ventana documentada de doble lectura o doble escritura.
- Elimine la ruta anterior solo después de que se comprenda el uso y el comportamiento del historial retenido.
Continúe con tipos de datos de eventos y capacidad de nulidad, consultando JSON anidado, catálogo de esquemas de eventos y receta de tasa nula de campo obligatorio.