Saltar al contenido

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 boto3
2
3s3 = 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')
6
7# Crear bucket
8s3.create_bucket(
9 Bucket='datalake-empresa',
10 CreateBucketConfiguration={'LocationConstraint': 'eu-west-1'}
11)
12
13# 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)
20
21# 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 365
2lifecycle_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}
16
17s3.put_bucket_lifecycle_configuration(
18 Bucket='datalake-empresa',
19 LifecycleConfiguration=lifecycle_config
20)
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 bucket
2s3.put_bucket_versioning(
3 Bucket='datalake-empresa',
4 VersioningConfiguration={'Status': 'Enabled'}
5)
6
7# 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}')
12
13# Listar versiones de un objeto
14versions = 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 TransferConfig
2
3# Configurar multipart: partes de 50MB, máximo 10 threads
4config = TransferConfig(
5 multipart_threshold=50 * 1024 * 1024, # 50MB
6 max_concurrency=10,
7 multipart_chunksize=50 * 1024 * 1024,
8)
9
10# 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=config
16)

Para archivos grandes, siempre usa upload_file con TransferConfig

La organización por zonas y particiones temporales es el estándar de la industria

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

[01]

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.

Cargando editor...
[02]

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).

Cargando editor...
[03]

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.

Cargando editor...
[04]

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.

Cargando editor...

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...