Imagen destacada del artículo: S3 por dentro: cómo funciona realmente un bucket

S3 por dentro: cómo funciona realmente un bucket

Durante años, muchos desarrolladores hemos tratado Amazon S3 como si fuera “un disco duro en la nube”. Subes archivos, los descargas, borras alguno y listo. Funciona, escala y casi nunca falla.

El problema es que esa simplificación es peligrosa.

Porque S3 no es un filesystem, no piensa como un filesystem y castiga silenciosamente a quien lo usa sin entenderlo.

He visto aplicaciones que funcionaban perfectamente en desarrollo colapsar en producción porque nadie entendió cómo S3 realmente opera. He debuggeado facturaciones de $10,000/mes que se redujeron a $500 simplemente cambiando cómo se nombraban los objetos.

Este artículo no va de features ni de tutoriales rápidos. Va de qué es realmente un bucket S3 por dentro, cómo está diseñado y por qué entender esto cambia la forma en la que diseñas sistemas en cloud.

Qué es realmente Amazon S3 (y qué no es)

Amazon Web Services S3 es un servicio de almacenamiento de objetos, no un sistema de archivos. Esto no es una diferencia semántica: es la base de todo.

Lo que NO tiene S3:

  • ❌ No hay carpetas reales
  • ❌ No hay jerarquía de directorios
  • ❌ No hay discos, bloques ni inodos
  • ❌ No hay “archivos” en el sentido tradicional

En S3 solo existen objetos identificados por una key dentro de un bucket. Las “carpetas” que ves en la consola de AWS son solo una ilusión visual basada en prefijos de texto.

Ejemplo que cambia tu perspectiva

Cuando escribes esto en la consola:

logs/2025/01/01/app.log

Para S3, eso no es una ruta. Es una cadena de texto completa. No existe el directorio logs/, ni 2025/, ni 01/. Solo existe un objeto con la key logs/2025/01/01/app.log.

Este detalle explica:

  • Por qué “listar una carpeta” puede ser lento
  • Por qué no puedes mover archivos (solo copiar + borrar)
  • Por qué los costes de operaciones pueden sorprenderte
  • Por qué algunos diseños funcionan terriblemente mal a escala

Bucket, objeto y key: el modelo mental correcto

Un bucket es un contenedor lógico global. El nombre es único en todo AWS (no solo en tu cuenta, en toda AWS a nivel mundial).

Dentro del bucket hay objetos.

Cada objeto tiene:

Objeto en S3:
  Key: "logs/2025/01/01/app.log"
  Content: [bytes del archivo]
  Metadata:
    - Content-Type: text/plain
    - Content-Length: 45632
    - ETag: "5eb63bbbe01eeed093cb22bb8f5acdc3"
    - Storage Class: STANDARD
    - Server-side encryption: AES256
  Tags:
    - Environment: production
    - Team: backend
  ACLs: [permisos de acceso]
  Versioning: [si está habilitado]

Lo que NO puedes hacer:

# ❌ Esto NO existe en S3
cd logs/2025/01/
ls

# ❌ Mover un archivo (no hay tal operación)
mv file.txt folder/file.txt

# ❌ Append a un archivo
echo "nueva línea" >> file.log

# ❌ Editar parte de un archivo
sed -i 's/old/new/' file.txt

Esto convierte a S3 en un servicio inmutable por diseño. Y esa inmutabilidad es una de sus mayores virtudes… si la sabes usar.

Durabilidad vs disponibilidad: las famosas “11 nueves”

Uno de los claims más repetidos de S3 es su 99.999999999% de durabilidad (11 nueves). Aquí suele haber confusión.

La diferencia crítica:

Durabilidad (11 nueves):
Probabilidad de que NO pierdas tus datos. S3 está diseñado para que, si almacenas 10,000,000 de objetos, estadísticamente perderás 1 cada 10,000 años.

Disponibilidad (99.99% para S3 Standard):
Probabilidad de poder acceder a tus datos cuando los solicites.

Cómo lo logra S3

S3 replica automáticamente los objetos en múltiples Availability Zones dentro de una región. No hablamos de 2 o 3 copias simples, hablamos de:

Objeto subido a S3:

Replicación automática:
  - Copia 1 → AZ-a (datacenter físico independiente)
  - Copia 2 → AZ-b (datacenter físico independiente)
  - Copia 3 → AZ-c (datacenter físico independiente)
  - Checksums → Verificación continua de integridad
  - Auto-reparación → Si detecta corrupción, reconstruye

Resultado:

  • ✅ Puedes tener una caída de AZ completa y no perder datos
  • ✅ Puedes no acceder temporalmente (mantenimiento), pero los datos siguen ahí
  • ✅ Protección contra bit rot (corrupción silenciosa de datos)

Este diseño explica por qué S3 es el backend natural de:

  • 💾 Backups críticos
  • 📊 Data lakes y analytics
  • 🗂️ Logs de aplicaciones
  • 📦 Artefactos de CI/CD
  • 🎬 Assets multimedia

Y también por qué no es buena idea usarlo como disco activo de una aplicación con muchas escrituras aleatorias.

Consistencia: lo que cambió (y por qué importa)

Durante años, S3 fue “eventually consistent” para algunos casos. Eso obligaba a diseños defensivos bastante feos:

# Código antiguo (pre-2020)
s3.put_object(Bucket='my-bucket', Key='data.json', Body=data)
time.sleep(1)  # 😱 Esperar a que se propague
response = s3.get_object(Bucket='my-bucket', Key='data.json')

El cambio de diciembre 2020

Hoy, S3 ofrece strong read-after-write consistency para TODAS las operaciones:

  • ✅ Lees inmediatamente lo que acabas de escribir
  • ✅ Borrados son inmediatamente visibles
  • ✅ Sobrescrituras son consistentes
  • ✅ Sin costo adicional, sin configuración
# Código actual
s3.put_object(Bucket='my-bucket', Key='data.json', Body=data)
# Inmediatamente disponible para lectura ✅
response = s3.get_object(Bucket='my-bucket', Key='data.json')

Esto lo hace más fácil de usar, sí. Pero no cambia su naturaleza: sigue siendo object storage, no un filesystem.

Muchos problemas actuales vienen de desarrolladores que escucharon “ya es consistente” y asumieron que podían tratarlo como NFS o EFS. Error.

Cómo escala S3 de verdad (y por qué no se parece a tu base de datos)

S3 está diseñado para:

  • 🚀 Escalar horizontalmente sin límite práctico
  • 📦 Manejar miles de millones de objetos por bucket
  • 🔥 Servir millones de requests concurrentes
  • 🌍 Distribuir carga globalmente (con CloudFront)

La arquitectura invisible

Internamente, S3 usa un sistema de particionamiento basado en el prefijo de las keys. Aunque AWS ha mejorado esto enormemente, la forma en que diseñas tus keys sigue importando.

Diseño malo (hot partition):

# Todos los logs del mismo día van al mismo prefijo
logs/2025-01-01/...
logs/2025-01-02/...
logs/2025-01-03/...

# Millones de objetos con el mismo prefijo del día
# Todas las escrituras se concentran en las mismas particiones

Diseño bueno (distribución uniforme):

# Hash del ID al principio distribuye la carga
a7f3/logs/2025-01-01/app.log
b2e9/logs/2025-01-01/app.log
c5d1/logs/2025-01-01/app.log

# O por usuario/tenant
user-12345/uploads/2025-01-01/photo.jpg
user-67890/uploads/2025-01-01/document.pdf

Rendimiento real

S3 Performance:
  Requests por segundo por prefijo:
    - PUT/COPY/POST/DELETE: 3,500 req/s
    - GET/HEAD: 5,500 req/s
  
  Transferencia:
    - Sin límite de ancho de banda total
    - Multi-part upload: hasta 5 TB por objeto
    - Transferencia acelerada: +50-500% velocidad

Un SRE no piensa “¿funciona?”, piensa:
“¿Cómo va a comportarse esto dentro de 6 meses con 100x tráfico?”

Storage Classes: no todo cuesta lo mismo

Una de las mayores ventajas de S3 es que puedes optimizar costes eligiendo la clase de almacenamiento adecuada:

S3 Storage Classes:
  
  S3 Standard:
    - Uso: Datos de acceso frecuente
    - Durabilidad: 11 nueves
    - Disponibilidad: 99.99%
    - Coste: ~$0.023/GB/mes
    - Latencia: milisegundos
  
  S3 Intelligent-Tiering:
    - Uso: Patrones de acceso impredecibles
    - Mueve automáticamente entre tiers
    - Sin costes de recuperación
    - Ideal para: No sabes el patrón de uso
  
  S3 Standard-IA (Infrequent Access):
    - Uso: Acceso < 1 vez/mes
    - Coste storage: ~$0.0125/GB/mes
    - Coste retrieval: $0.01/GB
    - Ideal para: Backups mensuales
  
  S3 Glacier Instant Retrieval:
    - Uso: Datos de archivo, acceso trimestral
    - Coste: ~$0.004/GB/mes
    - Latencia: milisegundos
    - Ideal para: Archivos médicos, regulatorios
  
  S3 Glacier Flexible Retrieval:
    - Coste: ~$0.0036/GB/mes
    - Latencia: 1-5 minutos (Expedited) a 12 horas
    - Ideal para: Backups anuales
  
  S3 Glacier Deep Archive:
    - Uso: Retención a largo plazo
    - Coste: ~$0.00099/GB/mes
    - Latencia: 12-48 horas
    - Ideal para: Compliance de 7-10 años

Caso real: optimización de costes

Antes:

Bucket con 500 TB de logs de 5 años
Todo en S3 Standard
Coste mensual: ~$11,500

Después (con Lifecycle Policies):

Lifecycle Policy:
  - Logs < 30 días: S3 Standard
  - Logs 30-90 días: S3 Standard-IA
  - Logs 90-365 días: S3 Glacier Instant
  - Logs > 1 año: S3 Glacier Deep Archive
  
Coste mensual: ~$2,400
Ahorro: $9,100/mes ($109,200/año)

Versionado y protección contra borrados

S3 Versioning es una de las features más infrautilizadas y potencialmente más valiosas:

# Habilitar versionado
resource "aws_s3_bucket_versioning" "main" {
  bucket = aws_s3_bucket.main.id
  
  versioning_configuration {
    status = "Enabled"
  }
}

Qué hace:

  • Cada vez que sobrescribes un objeto, S3 guarda la versión anterior
  • Los borrados son “soft deletes” (se marca con delete marker)
  • Puedes recuperar cualquier versión anterior

Caso de uso real:

# Usuario borra accidentalmente archivo crítico
aws s3 rm s3://my-bucket/critical-data.json

# Sin versionado: datos perdidos ❌
# Con versionado: recuperación inmediata ✅

# Listar versiones
aws s3api list-object-versions \
  --bucket my-bucket \
  --prefix critical-data.json

# Restaurar versión anterior
aws s3api delete-object \
  --bucket my-bucket \
  --key critical-data.json \
  --version-id [delete-marker-id]

Casos de uso reales (y por qué funcionan bien)

S3 brilla cuando lo usas como:

1. Almacenamiento de logs inmutables

# Pattern: fecha + servicio + ID único
logs/2025/01/03/api-server/req-a7f3b2e9.json
logs/2025/01/03/worker/job-c5d1f8a4.json

Por qué funciona:

  • Write-once, read-many
  • No hay updates ni deletes frecuentes
  • Lifecycle policies para mover a Glacier automáticamente

2. Artifacts de CI/CD

artifacts/backend/v1.2.3/backend.tar.gz
artifacts/frontend/v2.4.1/dist.zip

Por qué funciona:

  • Inmutables por naturaleza
  • Versionado natural con el path
  • CloudFront para distribución rápida

3. Static Site Hosting

# Website estático + CloudFront
s3://my-website-bucket/
├── index.html
├── css/
├── js/
└── images/

Por qué funciona:

  • Assets estáticos
  • Caching agresivo
  • Integración nativa con CloudFront CDN

4. Data Lakes y Analytics

# Particionado por fecha para Athena/Spark
data/events/year=2025/month=01/day=03/events.parquet

Por qué funciona:

  • Esquema optimizado para queries
  • Integraciones con Athena, Glue, EMR
  • Costes muy bajos para almacenamiento masivo

El error clásico del backend developer

El patrón más común que he visto:

# ❌ Anti-pattern: usar S3 como database
def update_user_profile(user_id, data):
    # Leer objeto completo
    obj = s3.get_object(Bucket='profiles', Key=f'{user_id}.json')
    profile = json.loads(obj['Body'].read())
    
    # Modificar
    profile['last_login'] = datetime.now()
    
    # Escribir completo (¡reescritura total!)
    s3.put_object(
        Bucket='profiles',
        Key=f'{user_id}.json',
        Body=json.dumps(profile)
    )

Problemas:

  • Cada update reescribe el objeto completo
  • Costes de requests innecesarios
  • Latencia alta para operaciones frecuentes
  • No es atómico (race conditions)

Solución correcta:

# ✅ Para datos transaccionales: DynamoDB
# ✅ Para archivos inmutables: S3
# ✅ Para cache: ElastiCache

# S3 solo para:
s3.put_object(
    Bucket='user-uploads',
    Key=f'{user_id}/profile-pic.jpg',
    Body=image_data
)

Seguridad: no dejes tus buckets abiertos

He visto buckets S3 expuestos en auditorías de seguridad más veces de las que me gustaría admitir.

Checklist de seguridad básica:

Seguridad S3:
  ✅ Block Public Access habilitado (por defecto desde 2023)
  ✅ Bucket policies restrictivas
  ✅ IAM roles en lugar de access keys
  ✅ Encryption at rest (SSE-S3 o SSE-KMS)
  ✅ Encryption in transit (HTTPS obligatorio)
  ✅ Versioning habilitado
  ✅ MFA Delete para buckets críticos
  ✅ Access Logging habilitado
  ✅ CloudTrail para auditoría

Bucket Policy ejemplo:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "EnforceHTTPS",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::my-bucket/*"
      ],
      "Condition": {
        "Bool": {
          "aws:SecureTransport": "false"
        }
      }
    }
  ]
}

Costes: dónde se va tu dinero realmente

Desglose de costes S3:
  
  Storage:
    - $0.023/GB/mes (Standard)
    - Facturado por GB-mes
  
  Requests:
    - PUT/POST: $0.005 por 1,000 requests
    - GET: $0.0004 por 1,000 requests
    - DELETE/LIST: gratis
  
  Data Transfer:
    - Ingress (subir): GRATIS
    - Egress (descargar): $0.09/GB (primeros 10 TB)
    - Entre regiones: $0.02/GB
    - A CloudFront: GRATIS ✅
  
  Retrieval (IA/Glacier):
    - Standard-IA: $0.01/GB
    - Glacier: $0.01-$0.03/GB según velocidad

Optimización típica:

# Antes: descargar desde S3 directamente
GET https://my-bucket.s3.amazonaws.com/file.jpg
Coste: $0.09/GB

# Después: servir vía CloudFront
GET https://d111111abcdef8.cloudfront.net/file.jpg
Coste: $0.085/GB + caching + mejor performance

La idea clave para cerrar

S3 no es simple. Es simple de usar, que no es lo mismo.

Cuando entiendes cómo funciona un bucket por dentro:

  • ✅ Diseñas buckets que escalan sin rediseño
  • ✅ Optimizas costes desde el primer día
  • ✅ Evitas problemas de rendimiento predecibles
  • ✅ Implementas seguridad correctamente
  • ✅ Duermes más tranquilo sabiendo que tus datos están seguros

Y, casi sin darte cuenta, empiezas a pensar como Cloud Engineer o SRE, no solo como desarrollador backend.

La diferencia entre usar S3 y entender S3 es la diferencia entre “funciona” y “funciona bien a escala durante años”.