lección 6
Día 4 -- Optimización: compresión Iceberg, particionado y Z-order
El data lake de 12,3 TB crece 40 GB/día hoy y crecerá 100 cuando entren los sensores de vibración a 5 Hz. Optimizas el almacenamiento con retención, compresión Zstandard, compaction y Z-order. Reduces el tamaño hasta ~80% (según cuántos días de raw se conserven) y aceleras las consultas de Patricia.
⏱ 35 min
## Jueves, 9:00 AM -- El coste del lake
Fernando te pide sentarte con el un momento antes del standup. "Ayer recibi la factura de AWS del mes pasado. El data lake de S3 nos cuesta 3.200 EUR/mes y crece un 8% mensual. A este ritmo, en 6 meses serán 5.000 EUR/mes solo de storage. Kenji me dice que hay margen de optimización pero nunca ha tenido tiempo de hacerlo. Quiero que dediques hoy a esto. Entregable: un plan de optimización con las cuatro palancas y lo que ahorra cada una, con números de antes/después."
Fernando se levanta y añade una cosa antes de irse: "Y hay algo que me ha dicho Kenji y que no me gusta: esos 5.000 euros son la cuenta ingenua, la de suponer que seguimos creciendo igual. Con los sensores de vibración que vas a meter en producción el mes que viene, el lake crece dos veces y media más deprisa, así que la cifra de dentro de seis meses es bastante peor. O lo arreglamos ahora o lo arreglamos con el triple de datos encima. Prefiero ahora."
Revisas las métricas del lake con Kenji:
- Tamano total: 12.3 TB en S3 (zona raw: 4.1 TB, silver: 5.2 TB, gold: 3.0 TB), acumulados en los 18 meses que lleva la plataforma
- Crecimiento diario actual: ~40 GB/día (la vibración aporta unos 15 GB/día, el 37% de lo que entra), y subiendo: la media de los 18 meses son 22 GB/día
- Crecimiento previsto para dentro de un mes: ~100 GB/día, dos veces y media más, cuando entren en producción los sensores de vibración a 5 Hz que diseñaste el lunes. La vibración pasará a ser el 75% de lo que entra
- Formato: Parquet con compresión Snappy (default de Spark)
- Particionado: por fecha (dt=YYYY-MM-DD) en todas las tablas
- Archivos: muchos archivos pequeños (problema de "small files") -- en la tabla de vibración, promedio 8 MB/archivo, unos 2.880 archivos por particion al día
- Queries tipicas de Patricia: filtrar por machine_id + rango de fecha. Full scan actual.
- Queries de BMW export: filtrar por batch_id + fecha. Tambien full scan.
- Retencion: sin politica definida. Datos de hace 18 meses siguen en la zona raw, ocupando 4.1 TB por inercia.
Los 4 problemas principales que identificas. Los dos primeros reducen tamaño (y factura); los otros dos compran velocidad de consulta y no bajan el tamaño:
- 01.COMPRESION SUBOPTIMA: Snappy es rápido pero comprime 2:1. Zstandard nivel 3 llega a 4:1 con datos de sensores (números que se repiten mucho) sin penalización de lectura significativa. Lo que hoy ocupa 12,3 TB comprimido a la mitad ocupa 6,2 TB.
- 02.SMALL FILES: El streaming escribe un archivo por micro-batch (cada 30 segundos). En un día = 2.880 archivos por particion en la tabla de vibración. Overhead de metadata en Iceberg y latencia de listing en S3. Necesitas compaction. No reduce tamaño: reduce latencia de consulta.
- 03.PARTICIONADO INEFICIENTE: Solo por fecha. Cuando Patricia busca "maquina X en los últimos 7 días", Spark escanea TODAS las maquinas de esos 7 días. Con reordenación de datos (Z-order) dentro de cada particion, Spark puede saltar ficheros enteros (data skipping). Tampoco reduce tamaño: reduce latencia.
- 04.SIN POLÍTICA DE RETENCIÓN: hay datos de hace dieciocho meses en la zona raw (la copia sin procesar de lo que entró). No hay ninguna consulta regular sobre ella ni ninguna decisión sobre cuánto guardarla: ocupa 4,1 TB por inercia. Es la medida que más reduce hoy y la única que pone un techo a lo que el lake puede llegar a ocupar. Ojo: es también la única irreversible -- lo que borras no vuelve, así que la decisión de cuántos días no es técnica (lo ves en el ejercicio 2).
Cuidado al sumar ahorros: no se suman, se multiplican sobre lo que va quedando. La retención deja el lake en torno al 39% de lo que era (unos 4,8 TB), y encima la compresión lo divide por dos: acabas cerca de 2,4 TB, un 80% menos que los 12,3 de hoy. Un 61% y un 50% no dan 111%, dan 80%. Y hacen cosas distintas en el tiempo: la retención baja el suelo una vez y el lake vuelve a crecer desde ahí; la compresión divide por dos todo lo que entre a partir de mañana. Por eso se hacen las dos, y en este orden: primero la retención y después la recompresión, porque recomprimir cuatro teras que vas a borrar en treinta días es tirar el dinero.
## Solucion 1: Migracion a Zstandard
Zstandard (zstd) nivel 3 ofrece ratio de compresión 2x mejor que Snappy con velocidad de descompresion similar. Para datos de sensores (valores numericos con alta repetitividad), el ratio mejora aun más. El mismo dato original, una compresión el doble de buena, la mitad de espacio: los 12,3 TB de hoy pasan a unos 6,2 TB. El cambio se aplica en la configuración de escritura de Iceberg -- los archivos existentes se pueden reescribir con un job de compaction.
## Solucion 2: Compaction automática
Iceberg tiene una accion de compaction (rewriteDataFiles) que fusiona archivos pequeños en archivos grandes. El objetivo: archivos de 256-512 MB (optimo para S3 y Spark). Un DAG de Airflow ejecuta la compaction cada 6 horas, fusionando los archivos del streaming.
## Solucion 3: Z-order por machine_id y batch_id
Dentro de cada partición de fecha, los datos se pueden reordenar para que las consultas salten ficheros enteros. Iceberg guarda el mínimo y el máximo de cada columna en cada fichero, así que si los datos de una máquina están juntos, Spark abre solo los ficheros que pueden contenerla. Sin esa reordenación, Spark debe abrir todos los archivos de la particion.
Si solo tuvieras una consulta, bastaría con ordenar por su columna (un sort). Pero aquí hay dos consultas con claves distintas: Patricia filtra por machine_id y el export de BMW filtra por batch_id. Ordenar por máquina deja los lotes repartidos por todos los ficheros, igual que están ahora. Para eso está el Z-order: entrelaza los valores de las dos columnas de manera que los datos queden agrupados en las dos dimensiones a la vez. No es tan bueno como ordenar por una sola -- para la consulta de Patricia, un sort puro sería algo mejor -- pero sirve para las dos, que es lo que necesitas. Regla práctica: una columna, ordena; dos o tres, Z-order; más de tres o cuatro deja de compensar, porque el entrelazado se diluye y ya no salta casi nada.
Dos condiciones para que el Z-order sirva de verdad aquí. Primera: que las dos consultas vayan contra la MISMA tabla. Si el export de BMW lee una tabla de calidad distinta de la de vibración, entonces cada tabla se ordena por lo suyo con un sort y no hace falta Z-order en ninguna. Segunda: la consulta de BMW hoy hace full scan, y un escaneo completo no se beneficia del data skipping por definición. El Z-order solo le sirve si el export empieza filtrando por batch_id en vez de leerlo todo -- y eso es un cambio en el export, no en el lake.
Z-order vs particionado adicional: podrias particionar por (fecha, machine_id) en lugar de usar Z-order. Pero con 340 maquinas x 365 días = 124.100 particiones. Demasiadas -- y el problema no es tanto que el catálogo de Iceberg se vuelva lento (Iceberg está pensado justo para no tener que listar particiones) como que cada partición quedaría diminuta, un día de una sola máquina, reproduciendo el problema de ficheros pequeños que este día entero intenta resolver. Z-order da el beneficio de query sin multiplicar particiones.
Cuidado con la compaction: mientras un job de compaction está reescribiendo archivos, los lectores siguen viendo los archivos originales (isolation de Iceberg). Pero si el job falla a mitad, no hay problema -- Iceberg usa commits atomicos. Los archivos nuevos solo son visibles cuando el commit se completa.
## Lo que la optimización cuesta
Una optimización de coste que no cuenta su propio coste no es un plan, es una promesa -- y es la primera pregunta que Fernando va a hacer, porque es su factura la que mira. La migración a Zstandard es un pago único: hay que leer los 12,3 TB, recomprimirlos y volver a escribirlos. Son horas de clúster y varios millones de peticiones a S3, y conviene hacerlo por tramos (una zona, un mes) y no todo de golpe, para poder parar si algo va mal. Y hazlo después de aplicar la retención, no antes: recomprimir cuatro teras que vas a borrar dentro de treinta días es tirar el dinero dos veces. El orden de las medidas cambia el coste del plan por un factor de tres.
La compaction, en cambio, es un pago recurrente: cada seis horas vuelve a leer y escribir lo que ha entrado desde la vez anterior -- solo eso, no la partición entera; si la configuras para reescribir ficheros ya compactados, pagas lo mismo todos los días para nada. Es dinero todos los días, para siempre, a cambio de que las consultas sean rápidas y de que el catálogo no se llene de metadatos. Suele compensar de largo, pero va en la tabla de antes y después con su cifra. Lo que le presentas a Fernando no es "ahorro un 80%": es "ahorro un 80% de aquí en adelante, me cuesta esto una vez y esto todos los meses, y se paga solo en tantas semanas". Esa última frase es la que hace que te aprueben el plan.
El lake no adelgaza el día que lanzas la compaction. Iceberg no borra los ficheros viejos al reescribirlos: los deja como parte de los snapshots anteriores para que puedas volver atrás. Así que durante unos días tienes las dos copias y la factura sube antes de bajar. Lo que libera el espacio de verdad es expire_snapshots, y hasta que no se ejecuta no se ve nada. Por eso el plan tiene que llevar las tres cosas seguidas -- compactar, expirar snapshots y borrar ficheros huérfanos -- y por eso la métrica que le enseñas a Fernando no es la de mañana, es la del mes que viene. Dile eso antes, no después.
## comentarios
Reporta erratas, ayuda a otros o comparte tu opinión. Sé constructivo.
Inicia sesión para comentar y responder.
cargando comentarios...
Regístrate para guardar tu progreso.