Data Lake vs Data Warehouse — Guía de Arquitectura
Guía práctica de arquitectura Data Lake: almacenamiento estructurado vs no estructurado, conceptos de lakehouse, patrones ETL vs ELT y cuándo elegir un lake sobre un warehouse.
Nota para desarrolladores hispanohablantes: Esta guía incluye ejemplos y convenciones de nomenclatura adaptadas a equipos que trabajan en español. Cuando existen diferencias significativas en terminología técnica entre el inglés y el español, se indican explícitamente para facilitar la comunicación en equipos multiculturales.
Overview
Un Data Lake es un repositorio de almacenamiento centralizado que contiene datos estructurados, semi-estructurados y no estructurados a cualquier escala. A diferencia de un Data Warehouse, que almacena datos procesados con schema-on-write en tablas rígidas, un Data Lake almacena datos crudos en su formato nativo con schema aplicado en lectura (schema-on-read). Esta flexibilidad lo hace ideal para machine learning, análisis exploratorio y almacenar datos cuya estructura aún no se conoce. Sin embargo, sin gobernanza, los lakes pueden convertirse en “data swamps” — desorganizados, no buscables y poco confiables.
Cuándo Usar un Data Lake
-
For alternatives, see Lakehouse Architecture — The Best of Both Worlds.
-
Necesitas almacenar diversos tipos de datos: JSON, CSV, Parquet, imágenes, videos, logs
-
Las cargas de trabajo de machine learning requieren datos crudos sin procesar
-
El volumen de datos excede lo que las bases de datos tradicionales pueden manejar rentablemente
-
Quieres diferir el diseño de schema hasta que los datos se consuman
-
Los datos históricos deben retenerse barato para análisis futuro
Data Lake vs Data Warehouse
| Dimensión | Data Lake | Data Warehouse |
|---|---|---|
| Tipos de datos | Todos (estructurados, semi, no estructurados) | Solo estructurados |
| Schema | Schema-on-read | Schema-on-write |
| Usuarios | Científicos de datos, ingenieros ML, analistas | Analistas de negocio, herramientas BI |
| Rendimiento de consulta | Variable, optimizado para batch | Rápido, optimizado para OLAP |
| Costo | Almacenamiento bajo, cómputo alto | Almacenamiento alto, cómputo optimizado |
| Calidad de datos | Crudos, pueden no estar validados | Curados, validados, confiables |
| Escala | Petabyte+ | Terabyte a Petabyte |
Capas de Arquitectura
Zona Raw (Bronze)
├── Datos sin procesar de fuentes
├── Retenidos en formato nativo
└── Almacenamiento barato, largo plazo
Zona Limpia (Silver)
├── Datos deduplicados y validados
├── Transformaciones básicas aplicadas
└── Schemas tipados forzados
Zona Curada (Gold)
├── Agregados listos para negocio
├── Optimizados para rendimiento de consulta
└── Usados por herramientas BI y aplicaciones
ETL vs ELT
| Patrón | Flujo | Mejor Para |
|---|---|---|
| ETL | Extract → Transform → Load | Data warehouses, requerimientos estrictos de schema |
| ELT | Extract → Load → Transform | Data lakes, flexibilidad de schema-on-read |
# Patrón ELT — carga cruda, transforma bajo demanda
import pandas as pd
from pyspark.sql import SparkSession
spark = SparkSession.builder.appName("DataLakeELT").getOrCreate()
# Extract: Leer logs JSON crudos desde S3
raw_df = spark.read.json("s3://datalake/raw/events/2024/01/")
# Load: Almacenar como Parquet en la zona Silver
raw_df.write.parquet("s3://datalake/silver/events/", mode="overwrite")
# Transform: Aplicar schema y agregaciones bajo lectura
cleaned_df = spark.read.parquet("s3://datalake/silver/events/")
cleaned_df.createOrReplaceTempView("events")
daily_metrics = spark.sql("""
SELECT
DATE(timestamp) as date,
event_type,
COUNT(*) as event_count,
COUNT(DISTINCT user_id) as unique_users
FROM events
WHERE timestamp >= '2024-01-01'
GROUP BY DATE(timestamp), event_type
""")
daily_metrics.write.parquet("s3://datalake/gold/daily_metrics/")
Formatos de Almacenamiento
| Formato | Tipo | Caso de Uso |
|---|---|---|
| CSV | Texto | Intercambio, legible por humanos |
| JSON | Semi-estructurado | APIs, datos anidados |
| Parquet | Columnar | Consultas analíticas, compresión |
| Avro | Basado en filas | Streaming, evolución de schema |
| ORC | Columnar | Cargas de trabajo Hive/Spark |
| Delta Lake | Capa | Transacciones ACID sobre lakes |
Ejemplo de Delta Lake
from delta import configure_spark_with_delta_pip
from pyspark.sql import SparkSession
builder = SparkSession.builder.appName("DeltaLakeExample") \
.config("spark.sql.extensions", "io.delta.sql.DeltaSparkSessionExtension")
spark = configure_spark_with_delta_pip(builder).getOrCreate()
# Escribir con garantías ACID
df.write.format("delta").mode("overwrite").save("/datalake/silver/orders")
# Time travel — consultar a partir de una versión específica
spark.read.format("delta").option("versionAsOf", 5).load("/datalake/silver/orders")
# Evolución de schema
df_with_new_column.write.format("delta") \
.mode("append") \
.option("mergeSchema", "true") \
.save("/datalake/silver/orders")
Errores Comunes
- El data swamp — volcar todo sin catalogar, gobernar o políticas de retención
- Sin estrategia de particionamiento — consultar lakes sin particionar es dolorosamente lento; particionar por fecha y/o región
- Usar lakes para OLTP — los lakes son para análisis, no cargas transaccionales
- Ignorar gobernanza de datos — sin catálogos de metadata y controles de acceso, los lakes se vuelven inusables
- Problema de archivos pequeños — escribir miles de archivos diminutos mata el rendimiento de consulta; compactar regularmente
Troubleshooting
- High latency between services: trace the request path. Look for synchronous chains, missing caching, and oversized payloads that cross network boundaries.
- Single point of failure: identify components without redundancy. Add replicas, failover, or circuit breakers before scaling traffic.
- Unexpected coupling between services: review shared databases, libraries, and schemas. Bound contexts should own their data and expose stable interfaces.
- Cost spikes after scaling: Reserved capacity or spot instances can reduce steady-state spend.
- Difficult to reason about the system: maintain architecture decision records and service dependency maps.
Temas Avanzados
Escenario Detallado: Pipeline de Eventos con Spark y Delta Lake
Sistema: Plataforma de analitica de e-commerce
Volumen: 50M eventos/dia (clicks, vistas, compras)
Almacenamiento: S3 con zonas Bronze/Silver/Gold
Motor: EMR con Spark 3.5
Arquitectura:
Fuentes -> Kinesis -> S3 Bronze (JSON crudo)
S3 Bronze -> Spark job -> S3 Silver (Parquet + Delta)
S3 Silver -> Spark job -> S3 Gold (Agregados)
S3 Gold -> Athena/Trino -> BI tools
Paso 1: Ingesta a Bronze
Kinesis Firehose escribe JSON crudo a s3://lake/bronze/events/dt=2026-07-11/
Particion por fecha (dt) para queries eficientes
Sin transformacion: datos exactamente como llegan
Paso 2: Bronze a Silver (limpieza)
$ spark-submit --master yarn \\
--num-executors 20 \\
--executor-memory 8g \\
bronze_to_silver.py
# bronze_to_silver.py
raw = spark.read.json("s3://lake/bronze/events/dt=2026-07-11/")
cleaned = raw.filter("user_id is not null") \\
.withColumn("event_time", to_timestamp("timestamp")) \\
.withColumn("event_date", to_date("event_time")) \\
.dropDuplicates(["event_id"])
cleaned.write.format("delta") \\
.mode("append") \\
.partitionBy("event_date") \\
.save("s3://lake/silver/events/")
Paso 3: Silver a Gold (agregados)
silver = spark.read.format("delta").load("s3://lake/silver/events/")
daily = silver.groupBy("event_date", "event_type") \\
.agg(count("*").alias("total_events"),
countDistinct("user_id").alias("unique_users"))
daily.write.format("delta") \\
.mode("overwrite") \\
.option("overwriteSchema", "true") \\
.save("s3://lake/gold/daily_events/")
Paso 4: Optimizacion
# Compactar archivos pequenos semanalmente
delta_table = DeltaTable.forPath(spark, "s3://lake/silver/events/")
delta_table.optimize().compact(minFileSize="10MB")
# Vacuum: eliminar versiones viejas (retener 7 dias)
delta_table.vacuum(retentionHours=168)
Monitoreo:
- CloudWatch: duracion de jobs, uso de memoria, archivos de salida
- Alerta si Silver tiene > 1000 archivos pequenos (< 1MB)
- Alerta si Gold no se actualiza en 24h
- Data quality: Great Expectations valida schema y nulls en Silver
Costo mensual estimado:
S3 storage (50TB): ~$1,150
EMR (20 ejecutores x 4h/dia): ~$800
Athena (queries BI): ~$200
Total: ~$2,150/mes
Como manejo la evolucion de schema en un Data Lake?
Usa formatos que soportan evolucion de schema: Parquet, Avro o Delta Lake. Con Delta Lake, la opcion mergeSchema anade nuevas columnas sin romper lecturas existentes. Para cambios mayores (renombrar columnas, cambiar tipos), usa versionado de tablas: events_v1, events_v2. Documenta el cambio en el catalogo de datos. Los consumidores deben usar nombres de columna, no posicion, para evitar roturas.
Cuando debo compactar archivos en el lake?
Compacta cuando el numero de archivos pequenos (< 10MB) supera los 1000 por particion. Los archivos pequenos degradan el rendimiento porque Spark/Trino deben abrir cada archivo individualmente. Ejecuta OPTIMIZE semanalmente para tablas Silver y mensualmente para tablas Gold. Despues de compactar, ejecuta VACUUM para eliminar versiones viejas y liberar espacio.
End of document. Review and update quarterly.
Lectura Adicional
- Documentación oficial: consulta la referencia actualizada del framework o herramienta utilizada.
- Guías relacionadas: explora las guías de data y data-warehouse para profundizar.
- Patrones complementarios: revisa los patrones de diseño aplicables a tu stack tecnológico.
- Postmortems públicos: estudia incidentes reales de equipos que enfrentaron problemas similares en producción.
Notas de Producción
- Despliega gradualmente usando canary o blue-green para detectar regresiones temprano.
- Configura alertas para errores, latencia p99 y tasa de fallos antes de habilitar en producción.
- Documenta el rollback en el runbook; prueba el procedimiento en staging al menos una vez por trimestre.
- Revisa logs estructurados con correlation IDs para trazar requests end-to-end en incidentes.
Puntos Clave
- Aplica data lake vs data warehouse — guía de arquitectura cuando necesites una solución práctica para tu caso de uso.
- Monitorea el rendimiento después de implementar; mide latencia, errores y uso de recursos antes y después.
- Revisa la sección de Troubleshooting ante errores comunes; la mayoría tienen causa raíz documentada con solución.
- Mantén dependencias actualizadas y ejecuta tests en CI para prevenir regresiones en producción.
Errores Comunes en Producción
- Tratar la guía como un checklist para completar una vez en lugar de una práctica por evolucionar.
- Adoptar cada recomendación de golpe en lugar de comenzar con un cambio medido.
- Saltar la evaluación de madurez e imponer prácticas avanzadas a un equipo no preparado.
- No actualizar runbooks y expectativas de guardia al introducir nuevas prácticas.
- Ignorar datos reales de incidentes al priorizar qué partes de la guía aplicar primero.
- No asignar un responsable que revise decisiones trimestralmente.
- Copiar ejemplos sin adaptarlos a las herramientas y restricciones reales del equipo.
- Olvidar medir resultados antes de agregar la siguiente mejora.
Related Resources
Arquitectura Lakehouse — Lo Mejor de Ambos Mundos
Guía práctica de arquitectura Lakehouse: combinar flexibilidad de almacenamiento de data lake con confiabilidad de data warehouse usando formatos de tabla abiertos.
GuideArquitectura Data Mesh — Propiedad de Datos Descentralizada
Guía práctica de Data Mesh: descentralizar la propiedad de datos a equipos de dominio, tratar datos como producto y habilitar infraestructura de datos self-serve.
GuideSharding de Base de Datos
Guía práctica sobre sharding de base de datos: elegir claves de shard, enrutar consultas, rebalancear datos y evitar errores comunes al escalar más allá de un solo nodo de base de datos.
Preguntas frecuentes
- ¿Cómo empiezo con esto en un proyecto existente?
- Empieza con una parte pequeña y aislada de tu codebase. Aplica los conceptos de esta guía a un módulo o servicio. Mide el impacto, luego expande a otras áreas.
- ¿Qué herramientas necesito?
- Las herramientas mencionadas throughout esta guía se listan en cada sección. La mayoría son open-source y ampliamente adoptadas. Consulta los recursos relacionados para instrucciones de setup.
- ¿Cómo mido el éxito después de implementar esto?
- Define métricas claras antes de empezar: benchmarks de rendimiento, tasas de error o indicadores de mantenibilidad. Compara antes y después. Itera basándote en datos, no en suposiciones.