← Todos los casos
Operar

El pipeline que "funcionaba": confiabilidad del flujo de datos hacia el data lake

~6 hmenos de retraso en los datos entregados a BI

Funcionaba, pero nadie confiaba

Todos los días, un flujo automático llevaba los datos de producción al data lake de BI. Primero restauraba el dump más reciente de la base en un PostgreSQL dedicado. Después, Airbyte replicaba esa base por CDC. Por último, todo se cargaba en BigQuery.

Los jobs corrían, a veces fallaban y se repetían. En el panel, el pipeline funcionaba. Pero BI se quejaba de que los datos llegaban siempre atrasados, los syncs tardaban de 2 a 11 horas, y algunos días terminaban sin ingerir nada.

Siempre un día atrasado

Lo primero que llamó la atención fue que BigQuery mostraba una foto de la base de las 21h del día anterior, aun con el sync corriendo de madrugada. Crucé los horarios de los CronJobs y la explicación era simple: el restore tomaba el dump más reciente disponible, pero corría antes de que el backup de la madrugada llegara al bucket. Siempre tomaba el de las 21h. Moví el restore para después del backup, en el clúster y en Git, y el atraso de los datos para BI bajó unas seis horas.

En el mismo lugar estaba el motivo de que cada sync recorriera las 153 tablas enteras: recrear la base en cada restore destruía el slot de replicación del CDC.

Fallas que no hacían ruido

Después vinieron las fallas silenciosas, una por una. Un paso de corrección de schema nunca había funcionado: faltaba una biblioteca en la imagen, y el error se lo tragaban tres bloques except y un exit 0. El paso "pasaba" en cuatro segundos sin hacer nada. Reconstruí la imagen con el script corregido, con simulación por defecto y falla explícita en el log.

Una tabla tenía una columna con el mismo nombre que ella, y BigQuery interpretaba el identificador como la fila entera, y no como la columna. Recorrí los 157 streams para confirmar que era el único caso. Ese problema costaba una pasada completa de unos 50 GB por día.

El servidor de Airbyte también se caía solo: una rutina interna intentaba cancelar un job con un id inválido cada minuto y reventaba los 6 GB de heap. Y la alerta del sync mentía, con un timeout de seis horas que acusaba falla en syncs que terminaban con éxito poco después. Fueron cuatro falsas alarmas en 50 días.

Después de esas correcciones, el sync siguiente cerró en el primer intento.

El error 500 de todos los días

El error más frecuente era un 500 de BigQuery en el upload. La API de Airbyte reventaba la memoria del servidor cuando yo pedía el historial, así que leí las fallas intento por intento directo en su base interna. El conector subía unos 2,5 GB en un único upload, sin área intermedia. Un 500 a la mitad mataba el intento entero, que empezaba de cero. Medí 7,7 veces el trabajo necesario en un job y unas 45 horas de intentos perdidos en 27 días.

Escribí el post-mortem con la línea de tiempo y los datos de esos 27 días. Probé la actualización del conector, pero como hipótesis, no como corrección, y comparé el resultado con la línea base. La diferencia estaba dentro del ruido: no lo había resuelto. La documentación de BigQuery recomienda, para archivos grandes, cargar desde Cloud Storage, donde reintentar con backoff exponencial es suficiente. Abrí ese estudio como próximo paso, con costo, permisos, validación y rollback.

GitOps diciendo que todo estaba bien

En otro producto, Airbyte estuvo 24 horas caído mientras ArgoCD mostraba la aplicación sincronizada y sana. El chart declaraba la ServiceAccount como hook de Helm, y ArgoCD no incluye los hooks en el estado deseado. Cuando se borró, nada la recreó. Restauré la cuenta, versioné los recursos como objetos normales y documenté un segundo desvío: una política de sincronización activa en el clúster que no existía en Git.

También ayudé a preparar el backup que alimenta el pipeline para que se cifrara con KMS, con la separación de privilegios probada en la práctica: la credencial del backup puede generar una clave de datos, pero recibe acceso denegado al intentar descifrar.

Qué cambió

Los datos llegaron a BI con unas seis horas menos de atraso. Las cuatro fallas silenciosas se eliminaron, y el sync empezó a cerrar en el primer intento. La causa del error más frecuente quedó determinada en un post-mortem, con la siguiente solución basada en la recomendación oficial del proveedor.

Lo que me llevo

Una hipótesis probada no es un problema corregido. Actualizar el conector parecía resolverlo, y habría sido fácil declarar victoria. Compararlo con la línea base mostró que no, y eso evitó que el equipo dejara de buscar la solución real.

Y un pipeline de datos también necesita SRE. Un paso que termina con exit 0 sin hacer nada es peor que uno que falla, porque nadie va a buscarlo.