lección 3
S3 en profundidad: el almacenamiento infinito
Buckets, objetos, prefijos, clases de almacenamiento, lifecycle policies, versionado y access points. S3 es el corazón de todo data lake en AWS.
⏱ 60 min
Si tuviera que elegir UN solo servicio de AWS para enseñar a un ingeniero de datos junior, sería S3. Sin dudarlo un segundo. S3 (Simple Storage Service) es el cimiento sobre el que se construye absolutamente todo en el ecosistema de datos de AWS. Tu data lake vive en S3. Athena consulta S3. Glue lee y escribe en S3. EMR procesa datos de S3. Redshift carga desde S3. Lambda se triggerea por eventos de S3. Es el disco duro infinito de la nube.
S3 fue el primer servicio que AWS lanzó (marzo 2006) y hoy almacena más de 500 billones de objetos y sirve más de 200 millones de peticiones por segundo. Netflix guarda ahí sus masters de vídeo. Airbnb sus fotos. Spotify su catálogo. Y miles de empresas de datos guardan terabytes de Parquet, JSON y CSV esperando ser procesados. Vamos a dominarlo.
### Anatomía de S3: buckets y objetos
S3 tiene un modelo mental muy simple: hay "buckets" (contenedores) y dentro de los buckets hay "objetos" (archivos). Un bucket es como una carpeta raíz con un nombre único globalmente — no pueden existir dos buckets con el mismo nombre EN TODO AWS, no solo en tu cuenta. Dentro del bucket, cada objeto tiene una "key" (la ruta) y un "value" (los bytes del archivo).
Pero ojo: S3 NO es un sistema de archivos. No hay directorios reales. Cuando ves "datos/2024/01/ventas.parquet", esa barra "/" es parte del nombre (key) del objeto, no un separador de carpetas. S3 es un almacén de key-value plano. La consola de AWS te muestra "carpetas" por comodidad visual, pero internamente todo es plano. Esto importa cuando programas: no puedes "listar un directorio" directamente, sino filtrar objetos por prefijo.
1import boto323s3 = boto3.client('s3', endpoint_url='http://localhost:4566',4 aws_access_key_id='test', aws_secret_access_key='test',5 region_name='eu-west-1')67# Crear bucket8s3.create_bucket(9 Bucket='datalake-empresa',10 CreateBucketConfiguration={'LocationConstraint': 'eu-west-1'}11)1213# Subir un objeto (simula un archivo CSV)14datos_csv = "id,nombre,ventas\n1,Ana,15000\n2,Luis,23000"15s3.put_object(16 Bucket='datalake-empresa',17 Key='raw/ventas/2024/01/ventas-diarias.csv',18 Body=datos_csv.encode('utf-8')19)2021# Listar objetos con prefijo (simula "ver una carpeta")22response = s3.list_objects_v2(23 Bucket='datalake-empresa',24 Prefix='raw/ventas/2024/'25)26for obj in response.get('Contents', []):27 print(f"{obj['Key']} ({obj['Size']} bytes)")
Crear bucket, subir objeto y listar por prefijo — las 3 operaciones básicas
### Organización de un data lake en S3: la convención de prefijos
Aunque S3 no tiene carpetas reales, la industria usa convenciones de prefijos para organizar data lakes. La más común es la estructura por zonas que ya conoces de la Skill 12:
- s3://datalake/raw/ — datos crudos tal como llegan de la fuente
- s3://datalake/processed/ — datos limpios y transformados (silver)
- s3://datalake/analytics/ — datos listos para consumo (gold)
- s3://datalake/raw/{fuente}/{año}/{mes}/{día}/ — particionado temporal
Esta convención no es técnicamente obligatoria (S3 no la impone), pero es un estándar de facto que facilita la vida enormemente. Cuando configuras Glue crawlers o Athena, los prefijos determinan las particiones. Si tus datos están bien organizados, las consultas son más rápidas y baratas.
### Clases de almacenamiento: no todo cuesta lo mismo
Aquí es donde S3 se pone interesante para el bolsillo. No todos los datos se acceden con la misma frecuencia. Los datos de hoy se consultan constantemente. Los del mes pasado, de vez en cuando. Los de hace 3 años, casi nunca. AWS ofrece diferentes "clases" de almacenamiento con precios decrecientes a cambio de mayor latencia de acceso:
- S3 Standard: acceso frecuente. ~$0.023/GB/mes. Para datos calientes.
- S3 Infrequent Access (IA): acceso raro. ~$0.0125/GB/mes. Cobra por lectura.
- S3 Glacier Instant: archivo con acceso en milisegundos. ~$0.004/GB/mes.
- S3 Glacier Deep Archive: archivo a largo plazo. ~$0.00099/GB/mes. Recuperación en 12h.
- S3 Intelligent-Tiering: AWS mueve automáticamente entre clases según el uso.
La analogía: S3 Standard es tu escritorio (acceso inmediato, espacio caro). IA es el mismo escritorio pero con un peaje por abrir el cajón — accedes igual de rápido (milisegundos, igual que Standard), pero pagas un extra por cada GB que lees y un mínimo de 30 días aunque borres antes. Glacier Flexible Retrieval es el trastero del sótano (tardas de minutos a horas en recuperar algo, pero cuesta una fracción). Deep Archive es un almacén externo (12 horas mínimo, pero casi gratis).
Consejo de senior: usa S3 Intelligent-Tiering para datos cuyo patrón de acceso no conoces. AWS monitoriza el uso y mueve objetos automáticamente a la clase más barata. Para un data lake típico, los datos raw de más de 30 días deberían moverse automáticamente a IA. Configura lifecycle rules desde el día uno.
### Lifecycle policies: automatizar el ciclo de vida
Las lifecycle policies son reglas automáticas que mueven o borran objetos según su antigüedad. Es como tener un empleado invisible que ordena tu almacén todos los días:
1# Configurar lifecycle: mover a IA tras 30 días, a Glacier tras 90, borrar tras 3652lifecycle_config = {3 'Rules': [4 {5 'ID': 'mover-datos-antiguos',6 'Status': 'Enabled',7 'Filter': {'Prefix': 'raw/'},8 'Transitions': [9 {'Days': 30, 'StorageClass': 'STANDARD_IA'},10 {'Days': 90, 'StorageClass': 'GLACIER'},11 ],12 'Expiration': {'Days': 365}13 }14 ]15}1617s3.put_bucket_lifecycle_configuration(18 Bucket='datalake-empresa',19 LifecycleConfiguration=lifecycle_config20)21print("✅ Lifecycle policy configurada")
Los datos raw se mueven automáticamente y se borran al año
### Versionado: nunca pierdas un archivo por error
El versionado de S3 es como tener Git para tus objetos. Cada vez que sobreescribes un archivo, S3 guarda la versión anterior. Si alguien borra un archivo por error (o un pipeline buggy sobreescribe datos buenos con basura), puedes recuperar la versión anterior. En un data lake, esto es CRÍTICO.
1# Activar versionado en el bucket2s3.put_bucket_versioning(3 Bucket='datalake-empresa',4 VersioningConfiguration={'Status': 'Enabled'}5)67# Subir un archivo dos veces (simula actualización)8s3.put_object(Bucket='datalake-empresa', Key='config/schema.json',9 Body=b'{"version": 1}')10s3.put_object(Bucket='datalake-empresa', Key='config/schema.json',11 Body=b'{"version": 2}')1213# Listar versiones de un objeto14versions = s3.list_object_versions(15 Bucket='datalake-empresa', Prefix='config/schema.json'16)17for v in versions.get('Versions', []):18 print(f"Version: {v['VersionId']} | Fecha: {v['LastModified']}")
Con versionado activo, nunca pierdes una versión anterior del archivo
El versionado multiplica el almacenamiento: cada versión ocupa espacio y se factura. Combina versionado con lifecycle policies para borrar versiones antiguas automáticamente (ejemplo: mantener solo las últimas 3 versiones o borrar versiones de más de 30 días).
### Multipart upload: subir archivos grandes
Cuando subes un archivo de más de 100MB a S3, deberías usar multipart upload. Divide el archivo en partes, las sube en paralelo y las ensambla en S3. Si una parte falla, solo se reintenta esa parte, no todo el archivo. boto3 lo hace automáticamente con el TransferManager:
1from boto3.s3.transfer import TransferConfig23# Configurar multipart: partes de 50MB, máximo 10 threads4config = TransferConfig(5 multipart_threshold=50 * 1024 * 1024, # 50MB6 max_concurrency=10,7 multipart_chunksize=50 * 1024 * 1024,8)910# Subir archivo grande (boto3 usa multipart automáticamente si supera el threshold)11s3.upload_file(12 'datos_grandes.parquet',13 'datalake-empresa',14 'raw/ventas/datos_grandes.parquet',15 Config=config16)
Para archivos grandes, siempre usa upload_file con TransferConfig
Consejo de senior: nombra tus buckets con un patrón consistente: {empresa}-{entorno}-{propósito}. Ejemplo: acme-prod-datalake, acme-dev-datalake, acme-prod-backups. Incluye siempre el entorno (dev/staging/prod) para no confundirlos. Y recuerda: los nombres de bucket son globales en TODO AWS, así que añade algo único como el account ID.
## ejercicios
Construir estructura de data lake
Crea un bucket y sube archivos simulados organizados en la estructura raw/processed/analytics con particionado por fecha. La empresa de e-commerce FashionStore necesita su data lake.
Configurar lifecycle para ahorro de costes
FashionStore gasta demasiado en S3. Configura una lifecycle policy que mueva datos raw a Infrequent Access tras 30 días, a Glacier tras 90 días, y los borre tras 1 año. Este ejercicio continúa el anterior: si te sale NoSuchBucket, ejecuta antes el ejercicio 1 (LocalStack no guarda nada entre reinicios).
Versionado y recuperación de datos borrados
Un ingeniero junior borró por error el archivo de configuración del pipeline. Activa versionado, simula el error y recupera el archivo desde la versión anterior. Este ejercicio continúa el anterior: si te sale NoSuchBucket, ejecuta antes el ejercicio 1.
Inventario y métricas de un bucket
El CFO quiere saber cuánto ocupa cada zona del data lake. Escribe una función que calcule el tamaño total y el número de objetos por prefijo de primer nivel. Este ejercicio continúa el anterior: si te sale NoSuchBucket, ejecuta antes el ejercicio 1.
Regístrate para guardar tu progreso.
## comentarios
Reporta erratas, ayuda a otros o comparte tu opinión. Sé constructivo.
Inicia sesión para comentar y responder.
cargando comentarios...